Add disney_group grouped park filter categories
- New disney_group query param on /api/assets (park, resort, office, springs, other) - Both list and map filter dropdowns show group options above individual parks - Backend uses IN queries for grouped park values - Map view handles groups via client-side PARK_GROUP_MAP Closes #69
This commit is contained in:
@@ -1065,6 +1065,7 @@ def list_assets(
|
|||||||
assigned_to: Optional[int] = Query(None),
|
assigned_to: Optional[int] = Query(None),
|
||||||
disney_park: Optional[str] = Query(None),
|
disney_park: Optional[str] = Query(None),
|
||||||
disney_filter: Optional[str] = Query(None),
|
disney_filter: Optional[str] = Query(None),
|
||||||
|
disney_group: Optional[str] = Query(None, description="Grouped park categories: park, resort, office, springs, other"),
|
||||||
q: Optional[str] = Query(None),
|
q: Optional[str] = Query(None),
|
||||||
no_dex_days: Optional[int] = Query(None, ge=1),
|
no_dex_days: Optional[int] = Query(None, ge=1),
|
||||||
has_gps: Optional[bool] = Query(None),
|
has_gps: Optional[bool] = Query(None),
|
||||||
@@ -1092,6 +1093,19 @@ def list_assets(
|
|||||||
conditions.append("is_disney = 1")
|
conditions.append("is_disney = 1")
|
||||||
elif disney_filter == "non_disney":
|
elif disney_filter == "non_disney":
|
||||||
conditions.append("(is_disney IS NULL OR is_disney = 0)")
|
conditions.append("(is_disney IS NULL OR is_disney = 0)")
|
||||||
|
if disney_group:
|
||||||
|
park_groups = {
|
||||||
|
"park": ["magic-kingdom", "epcot", "hollywood-studios", "animal-kingdom"],
|
||||||
|
"resort": ["resort"],
|
||||||
|
"office": ["office"],
|
||||||
|
"springs": ["disney-springs"],
|
||||||
|
"other": ["other"],
|
||||||
|
}
|
||||||
|
parks = park_groups.get(disney_group)
|
||||||
|
if parks:
|
||||||
|
placeholders = ",".join("?" * len(parks))
|
||||||
|
conditions.append(f"disney_park IN ({placeholders})")
|
||||||
|
params.extend(parks)
|
||||||
if model:
|
if model:
|
||||||
conditions.append("model = ?")
|
conditions.append("model = ?")
|
||||||
params.append(model)
|
params.append(model)
|
||||||
|
|||||||
+75
-13
@@ -1340,7 +1340,13 @@
|
|||||||
<div class="fp-label">Disney Park</div>
|
<div class="fp-label">Disney Park</div>
|
||||||
<select id="filterDisneyPark" class="input-field" onchange="onFilterChange()">
|
<select id="filterDisneyPark" class="input-field" onchange="onFilterChange()">
|
||||||
<option value="">All parks</option>
|
<option value="">All parks</option>
|
||||||
<option disabled>──────────</option>
|
<option disabled>──── Groups ────</option>
|
||||||
|
<option value="group:park">🏰 Disney Park (all parks)</option>
|
||||||
|
<option value="group:resort">🏨 Disney Resort</option>
|
||||||
|
<option value="group:office">🏢 Disney Office</option>
|
||||||
|
<option value="group:springs">🛍️ Disney Springs</option>
|
||||||
|
<option value="group:other">📍 Other Disney</option>
|
||||||
|
<option disabled>── Individual ──</option>
|
||||||
<option value="magic-kingdom">🏰 Magic Kingdom</option>
|
<option value="magic-kingdom">🏰 Magic Kingdom</option>
|
||||||
<option value="epcot">🌍 Epcot</option>
|
<option value="epcot">🌍 Epcot</option>
|
||||||
<option value="hollywood-studios">🎬 Hollywood Studios</option>
|
<option value="hollywood-studios">🎬 Hollywood Studios</option>
|
||||||
@@ -1550,7 +1556,13 @@
|
|||||||
<div class="fp-label">Disney Park</div>
|
<div class="fp-label">Disney Park</div>
|
||||||
<select id="mapFilterDisneyPark" class="input-field" onchange="onMapFilterChange()">
|
<select id="mapFilterDisneyPark" class="input-field" onchange="onMapFilterChange()">
|
||||||
<option value="">All parks</option>
|
<option value="">All parks</option>
|
||||||
<option disabled>──────────</option>
|
<option disabled>──── Groups ────</option>
|
||||||
|
<option value="group:park">🏰 Disney Park (all parks)</option>
|
||||||
|
<option value="group:resort">🏨 Disney Resort</option>
|
||||||
|
<option value="group:office">🏢 Disney Office</option>
|
||||||
|
<option value="group:springs">🛍️ Disney Springs</option>
|
||||||
|
<option value="group:other">📍 Other Disney</option>
|
||||||
|
<option disabled>── Individual ──</option>
|
||||||
<option value="magic-kingdom">🏰 Magic Kingdom</option>
|
<option value="magic-kingdom">🏰 Magic Kingdom</option>
|
||||||
<option value="epcot">🌍 Epcot</option>
|
<option value="epcot">🌍 Epcot</option>
|
||||||
<option value="hollywood-studios">🎬 Hollywood Studios</option>
|
<option value="hollywood-studios">🎬 Hollywood Studios</option>
|
||||||
@@ -3899,6 +3911,15 @@
|
|||||||
|
|
||||||
const PARK_ICONS = {'magic-kingdom':'🏰','epcot':'🌍','hollywood-studios':'🎬','animal-kingdom':'🌿','disney-springs':'🛍️','resort':'🏨','office':'🏢','other':'📍'};
|
const PARK_ICONS = {'magic-kingdom':'🏰','epcot':'🌍','hollywood-studios':'🎬','animal-kingdom':'🌿','disney-springs':'🛍️','resort':'🏨','office':'🏢','other':'📍'};
|
||||||
const PARK_NAMES = {'magic-kingdom':'Magic Kingdom','epcot':'Epcot','hollywood-studios':'Hollywood Studios','animal-kingdom':'Animal Kingdom','disney-springs':'Disney Springs','resort':'Resort','office':'Office','other':'Other'};
|
const PARK_NAMES = {'magic-kingdom':'Magic Kingdom','epcot':'Epcot','hollywood-studios':'Hollywood Studios','animal-kingdom':'Animal Kingdom','disney-springs':'Disney Springs','resort':'Resort','office':'Office','other':'Other'};
|
||||||
|
const PARK_GROUP_ICONS = {'park':'🏰','resort':'🏨','office':'🏢','springs':'🛍️','other':'📍'};
|
||||||
|
const PARK_GROUP_NAMES = {'park':'Disney Park','resort':'Disney Resort','office':'Disney Office','springs':'Disney Springs','other':'Other Disney'};
|
||||||
|
const PARK_GROUP_MAP = {
|
||||||
|
'park': ['magic-kingdom','epcot','hollywood-studios','animal-kingdom'],
|
||||||
|
'resort': ['resort'],
|
||||||
|
'office': ['office'],
|
||||||
|
'springs': ['disney-springs'],
|
||||||
|
'other': ['other'],
|
||||||
|
};
|
||||||
function catLabel(cat) {
|
function catLabel(cat) {
|
||||||
const e = CATEGORY_MAP[cat];
|
const e = CATEGORY_MAP[cat];
|
||||||
return e && e.label ? e.label : (cat || 'Other');
|
return e && e.label ? e.label : (cat || 'Other');
|
||||||
@@ -4124,7 +4145,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Filter state ──────────────────────────────────────────────────────
|
// ── Filter state ──────────────────────────────────────────────────────
|
||||||
let assetFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '',
|
let assetFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||||
let noDexFilterActive = false;
|
let noDexFilterActive = false;
|
||||||
let assetOffset = 0;
|
let assetOffset = 0;
|
||||||
@@ -4222,10 +4243,23 @@
|
|||||||
if (disneyFilterVal) {
|
if (disneyFilterVal) {
|
||||||
assetFilters.disney_filter = disneyFilterVal;
|
assetFilters.disney_filter = disneyFilterVal;
|
||||||
assetFilters.disney_park = null;
|
assetFilters.disney_park = null;
|
||||||
|
assetFilters.disney_group = null;
|
||||||
} else {
|
} else {
|
||||||
var parkVal = parkEl.value;
|
var parkVal = parkEl.value;
|
||||||
assetFilters.disney_park = parkVal || null;
|
if (parkVal && parkVal.startsWith('group:')) {
|
||||||
assetFilters.disney_filter = null;
|
// Grouped park category
|
||||||
|
assetFilters.disney_group = parkVal.replace('group:', '');
|
||||||
|
assetFilters.disney_park = null;
|
||||||
|
assetFilters.disney_filter = null;
|
||||||
|
} else if (parkVal) {
|
||||||
|
assetFilters.disney_park = parkVal;
|
||||||
|
assetFilters.disney_group = null;
|
||||||
|
assetFilters.disney_filter = null;
|
||||||
|
} else {
|
||||||
|
assetFilters.disney_park = null;
|
||||||
|
assetFilters.disney_group = null;
|
||||||
|
assetFilters.disney_filter = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assetFilters.customer_id = custEl.value || null;
|
assetFilters.customer_id = custEl.value || null;
|
||||||
|
|
||||||
@@ -4266,6 +4300,7 @@
|
|||||||
|
|
||||||
if (assetFilters.make) count++;
|
if (assetFilters.make) count++;
|
||||||
if (assetFilters.disney_park) count++;
|
if (assetFilters.disney_park) count++;
|
||||||
|
if (assetFilters.disney_group) count++;
|
||||||
if (assetFilters.disney_filter) count++;
|
if (assetFilters.disney_filter) count++;
|
||||||
if (assetFilters.customer_id) count++;
|
if (assetFilters.customer_id) count++;
|
||||||
if (assetFilters.location_id) count++;
|
if (assetFilters.location_id) count++;
|
||||||
@@ -4292,6 +4327,7 @@
|
|||||||
|
|
||||||
if (assetFilters.make) tags.push({key:'make', label:'\uD83C\uDFED ' + assetFilters.make});
|
if (assetFilters.make) tags.push({key:'make', label:'\uD83C\uDFED ' + assetFilters.make});
|
||||||
if (assetFilters.disney_park) tags.push({key:'disney_park', label: parkIcon(assetFilters.disney_park) + ' ' + parkName(assetFilters.disney_park)});
|
if (assetFilters.disney_park) tags.push({key:'disney_park', label: parkIcon(assetFilters.disney_park) + ' ' + parkName(assetFilters.disney_park)});
|
||||||
|
if (assetFilters.disney_group) tags.push({key:'disney_group', label: (PARK_GROUP_ICONS[assetFilters.disney_group] || '📍') + ' ' + (PARK_GROUP_NAMES[assetFilters.disney_group] || assetFilters.disney_group)});
|
||||||
if (assetFilters.disney_filter === 'disney') tags.push({key:'disney_filter', label:'🏰 Disney only'});
|
if (assetFilters.disney_filter === 'disney') tags.push({key:'disney_filter', label:'🏰 Disney only'});
|
||||||
if (assetFilters.disney_filter === 'non_disney') tags.push({key:'disney_filter', label:'🏢 Non-Disney'});
|
if (assetFilters.disney_filter === 'non_disney') tags.push({key:'disney_filter', label:'🏢 Non-Disney'});
|
||||||
if (assetFilters.customer_id) {
|
if (assetFilters.customer_id) {
|
||||||
@@ -4334,6 +4370,9 @@
|
|||||||
} else if (key === 'disney_park') {
|
} else if (key === 'disney_park') {
|
||||||
document.getElementById('filterDisneyPark').value = '';
|
document.getElementById('filterDisneyPark').value = '';
|
||||||
assetFilters.disney_park = null;
|
assetFilters.disney_park = null;
|
||||||
|
} else if (key === 'disney_group') {
|
||||||
|
document.getElementById('filterDisneyPark').value = '';
|
||||||
|
assetFilters.disney_group = null;
|
||||||
} else if (key === 'disney_filter') {
|
} else if (key === 'disney_filter') {
|
||||||
document.getElementById('filterDisneyFilter').value = '';
|
document.getElementById('filterDisneyFilter').value = '';
|
||||||
assetFilters.disney_filter = null;
|
assetFilters.disney_filter = null;
|
||||||
@@ -4363,7 +4402,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearAllFilters() {
|
function clearAllFilters() {
|
||||||
assetFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '',
|
assetFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||||
document.getElementById('assetSearch').value = '';
|
document.getElementById('assetSearch').value = '';
|
||||||
document.getElementById('clearSearch').style.display = 'none';
|
document.getElementById('clearSearch').style.display = 'none';
|
||||||
@@ -5001,6 +5040,7 @@
|
|||||||
|
|
||||||
if (assetFilters.make) params.set('make', assetFilters.make);
|
if (assetFilters.make) params.set('make', assetFilters.make);
|
||||||
if (assetFilters.disney_park) params.set('disney_park', assetFilters.disney_park);
|
if (assetFilters.disney_park) params.set('disney_park', assetFilters.disney_park);
|
||||||
|
if (assetFilters.disney_group) params.set('disney_group', assetFilters.disney_group);
|
||||||
if (assetFilters.disney_filter) params.set('disney_filter', assetFilters.disney_filter);
|
if (assetFilters.disney_filter) params.set('disney_filter', assetFilters.disney_filter);
|
||||||
if (assetFilters.q) params.set('q', assetFilters.q);
|
if (assetFilters.q) params.set('q', assetFilters.q);
|
||||||
if (assetFilters.customer_id) params.set('customer_id', assetFilters.customer_id);
|
if (assetFilters.customer_id) params.set('customer_id', assetFilters.customer_id);
|
||||||
@@ -5069,16 +5109,17 @@
|
|||||||
return parts.join('');
|
return parts.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFilter(category, status, make, disney_park) {
|
function setFilter(category, status, make, disney_park, disney_group) {
|
||||||
assetFilters.category = category;
|
assetFilters.category = category;
|
||||||
assetFilters.status = status;
|
assetFilters.status = status;
|
||||||
assetFilters.make = make;
|
assetFilters.make = make;
|
||||||
assetFilters.disney_park = disney_park;
|
assetFilters.disney_park = disney_park;
|
||||||
|
assetFilters.disney_group = disney_group || null;
|
||||||
assetFilters.disney_filter = null;
|
assetFilters.disney_filter = null;
|
||||||
// Sync dropdowns
|
// Sync dropdowns
|
||||||
if (document.getElementById('filterCategory')) document.getElementById('filterCategory').value = category || '';
|
if (document.getElementById('filterCategory')) document.getElementById('filterCategory').value = category || '';
|
||||||
if (document.getElementById('filterMake')) document.getElementById('filterMake').value = make || '';
|
if (document.getElementById('filterMake')) document.getElementById('filterMake').value = make || '';
|
||||||
if (document.getElementById('filterDisneyPark')) document.getElementById('filterDisneyPark').value = disney_park || '';
|
if (document.getElementById('filterDisneyPark')) document.getElementById('filterDisneyPark').value = (disney_group ? 'group:' + disney_group : (disney_park || ''));
|
||||||
|
|
||||||
renderActiveFilterTags();
|
renderActiveFilterTags();
|
||||||
assetOffset = 0;
|
assetOffset = 0;
|
||||||
@@ -6069,7 +6110,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Map filter state ──────────────────────────────────────────────────
|
// ── Map filter state ──────────────────────────────────────────────────
|
||||||
let mapFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '',
|
let mapFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||||
let mapFilterDropdownsLoaded = false;
|
let mapFilterDropdownsLoaded = false;
|
||||||
let _mapFilterTimer;
|
let _mapFilterTimer;
|
||||||
@@ -6128,10 +6169,22 @@
|
|||||||
if (disneyFilterVal) {
|
if (disneyFilterVal) {
|
||||||
mapFilters.disney_filter = disneyFilterVal;
|
mapFilters.disney_filter = disneyFilterVal;
|
||||||
mapFilters.disney_park = null;
|
mapFilters.disney_park = null;
|
||||||
|
mapFilters.disney_group = null;
|
||||||
} else {
|
} else {
|
||||||
var parkVal = document.getElementById('mapFilterDisneyPark').value;
|
var parkVal = document.getElementById('mapFilterDisneyPark').value;
|
||||||
mapFilters.disney_park = parkVal || null;
|
if (parkVal && parkVal.startsWith('group:')) {
|
||||||
mapFilters.disney_filter = null;
|
mapFilters.disney_group = parkVal.replace('group:', '');
|
||||||
|
mapFilters.disney_park = null;
|
||||||
|
mapFilters.disney_filter = null;
|
||||||
|
} else if (parkVal) {
|
||||||
|
mapFilters.disney_park = parkVal;
|
||||||
|
mapFilters.disney_group = null;
|
||||||
|
mapFilters.disney_filter = null;
|
||||||
|
} else {
|
||||||
|
mapFilters.disney_park = null;
|
||||||
|
mapFilters.disney_group = null;
|
||||||
|
mapFilters.disney_filter = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mapFilters.customer_id = document.getElementById('mapFilterCustomer').value || null;
|
mapFilters.customer_id = document.getElementById('mapFilterCustomer').value || null;
|
||||||
|
|
||||||
@@ -6172,6 +6225,7 @@
|
|||||||
if (mapFilters.category) count++;
|
if (mapFilters.category) count++;
|
||||||
if (mapFilters.make) count++;
|
if (mapFilters.make) count++;
|
||||||
if (mapFilters.disney_park) count++;
|
if (mapFilters.disney_park) count++;
|
||||||
|
if (mapFilters.disney_group) count++;
|
||||||
if (mapFilters.disney_filter) count++;
|
if (mapFilters.disney_filter) count++;
|
||||||
if (mapFilters.customer_id) count++;
|
if (mapFilters.customer_id) count++;
|
||||||
if (mapFilters.location_id) count++;
|
if (mapFilters.location_id) count++;
|
||||||
@@ -6196,6 +6250,7 @@
|
|||||||
if (mapFilters.category) tags.push({key:'category', label:'📂 ' + mapFilters.category});
|
if (mapFilters.category) tags.push({key:'category', label:'📂 ' + mapFilters.category});
|
||||||
if (mapFilters.make) tags.push({key:'make', label:'🏭 ' + mapFilters.make});
|
if (mapFilters.make) tags.push({key:'make', label:'🏭 ' + mapFilters.make});
|
||||||
if (mapFilters.disney_park) tags.push({key:'disney_park', label: parkIcon(mapFilters.disney_park) + ' ' + parkName(mapFilters.disney_park)});
|
if (mapFilters.disney_park) tags.push({key:'disney_park', label: parkIcon(mapFilters.disney_park) + ' ' + parkName(mapFilters.disney_park)});
|
||||||
|
if (mapFilters.disney_group) tags.push({key:'disney_group', label: (PARK_GROUP_ICONS[mapFilters.disney_group] || '📍') + ' ' + (PARK_GROUP_NAMES[mapFilters.disney_group] || mapFilters.disney_group)});
|
||||||
if (mapFilters.disney_filter === 'disney') tags.push({key:'disney_filter', label:'🏰 Disney only'});
|
if (mapFilters.disney_filter === 'disney') tags.push({key:'disney_filter', label:'🏰 Disney only'});
|
||||||
if (mapFilters.disney_filter === 'non_disney') tags.push({key:'disney_filter', label:'🏢 Non-Disney'});
|
if (mapFilters.disney_filter === 'non_disney') tags.push({key:'disney_filter', label:'🏢 Non-Disney'});
|
||||||
if (mapFilters.customer_id) {
|
if (mapFilters.customer_id) {
|
||||||
@@ -6229,6 +6284,9 @@
|
|||||||
} else if (key === 'disney_park') {
|
} else if (key === 'disney_park') {
|
||||||
document.getElementById('mapFilterDisneyPark').value = '';
|
document.getElementById('mapFilterDisneyPark').value = '';
|
||||||
mapFilters.disney_park = null;
|
mapFilters.disney_park = null;
|
||||||
|
} else if (key === 'disney_group') {
|
||||||
|
document.getElementById('mapFilterDisneyPark').value = '';
|
||||||
|
mapFilters.disney_group = null;
|
||||||
} else if (key === 'disney_filter') {
|
} else if (key === 'disney_filter') {
|
||||||
document.getElementById('mapFilterDisneyFilter').value = '';
|
document.getElementById('mapFilterDisneyFilter').value = '';
|
||||||
mapFilters.disney_filter = null;
|
mapFilters.disney_filter = null;
|
||||||
@@ -6253,7 +6311,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearMapFilters() {
|
function clearMapFilters() {
|
||||||
mapFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '',
|
mapFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||||
document.getElementById('mapSearchInput').value = '';
|
document.getElementById('mapSearchInput').value = '';
|
||||||
document.getElementById('mapFilterCategory').value = '';
|
document.getElementById('mapFilterCategory').value = '';
|
||||||
@@ -6310,7 +6368,11 @@
|
|||||||
// Disney/non-disney filter
|
// Disney/non-disney filter
|
||||||
if (mapFilters.disney_filter === 'disney' && !a.is_disney) return;
|
if (mapFilters.disney_filter === 'disney' && !a.is_disney) return;
|
||||||
if (mapFilters.disney_filter === 'non_disney' && a.is_disney) return;
|
if (mapFilters.disney_filter === 'non_disney' && a.is_disney) return;
|
||||||
// Disney park filter
|
// Disney park filter (individual or group)
|
||||||
|
if (mapFilters.disney_group) {
|
||||||
|
var groupParks = PARK_GROUP_MAP[mapFilters.disney_group] || [];
|
||||||
|
if (groupParks.indexOf(a.disney_park) === -1) return;
|
||||||
|
}
|
||||||
if (mapFilters.disney_park && a.disney_park !== mapFilters.disney_park) return;
|
if (mapFilters.disney_park && a.disney_park !== mapFilters.disney_park) return;
|
||||||
// Text search
|
// Text search
|
||||||
if (q) {
|
if (q) {
|
||||||
|
|||||||
Reference in New Issue
Block a user