Add Race workout kind with Garmin eventType auto-detection, sync-time running filter, and pill-based review queue filter
Race is the 8th fixed workout kind, seeded with a real (not placeholder) rule since Garmin Connect's eventType.typeKey reports "race" for manually-tagged race activities. Non-running activity types (padel, cycling, strength training, ...) are now dropped at sync time instead of being stored. The Review Queue's type filter is now clickable exclusive pill buttons instead of a dropdown.
This commit is contained in:
@@ -137,6 +137,25 @@ button:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.filter-pills {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.filter-pill {
|
||||
border-radius: 999px;
|
||||
padding: 0.35rem 0.9rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.filter-pill.active {
|
||||
background: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: #9aa0ab;
|
||||
}
|
||||
|
||||
@@ -59,25 +59,41 @@ export function ReviewQueue() {
|
||||
return items.filter((item) => candidates(item).some((c) => c.workout_kind_id === id));
|
||||
}, [items, filterKindId]);
|
||||
|
||||
function toggleFilter(id: string) {
|
||||
setFilterKindId((prev) => (prev === id ? "" : id));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<h2>Review Queue</h2>
|
||||
{error && <p className="error">{error}</p>}
|
||||
|
||||
{items.length > 0 && (
|
||||
<div className="controls">
|
||||
<label>
|
||||
Filter
|
||||
<select value={filterKindId} onChange={(e) => setFilterKindId(e.target.value)}>
|
||||
<option value="">All ({items.length})</option>
|
||||
<option value={UNSORTED}>Unsorted (no candidates)</option>
|
||||
{kinds.map((k) => (
|
||||
<option key={k.ID} value={k.ID}>
|
||||
{k.Name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<div className="filter-pills">
|
||||
<button
|
||||
type="button"
|
||||
className={`filter-pill${filterKindId === "" ? " active" : ""}`}
|
||||
onClick={() => toggleFilter("")}
|
||||
>
|
||||
All ({items.length})
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`filter-pill${filterKindId === UNSORTED ? " active" : ""}`}
|
||||
onClick={() => toggleFilter(UNSORTED)}
|
||||
>
|
||||
Unsorted (no candidates)
|
||||
</button>
|
||||
{kinds.map((k) => (
|
||||
<button
|
||||
key={k.ID}
|
||||
type="button"
|
||||
className={`filter-pill${filterKindId === String(k.ID) ? " active" : ""}`}
|
||||
onClick={() => toggleFilter(String(k.ID))}
|
||||
>
|
||||
{k.Name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user