v0.11.25 schedule list filter bug fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-backend",
|
"name": "jama-backend",
|
||||||
"version": "0.11.24",
|
"version": "0.11.25",
|
||||||
"description": "TeamChat backend server",
|
"description": "TeamChat backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.11.24}"
|
VERSION="${1:-0.11.25}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="jama"
|
IMAGE_NAME="jama"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-frontend",
|
"name": "jama-frontend",
|
||||||
"version": "0.11.24",
|
"version": "0.11.25",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ function MiniCalendar({ selected, onChange, eventDates=new Set() }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Mobile Filter Bar (Schedule view: keyword+type filters with month nav; Day view: calendar accordion) ──
|
// ── Mobile Filter Bar (Schedule view: keyword+type filters with month nav; Day view: calendar accordion) ──
|
||||||
function MobileScheduleFilter({ selected, onMonthChange, view, eventTypes, filterKeyword, onFilterKeyword, filterTypeId, onFilterTypeId, filterAvailability=false, onFilterAvailability, eventDates=new Set(), onInputFocus, onInputBlur }) {
|
function MobileScheduleFilter({ selected, onMonthChange, view, eventTypes, filterKeyword, onFilterKeyword, filterTypeId, onFilterTypeId, filterAvailability=false, onFilterAvailability, onClearFromDate, eventDates=new Set(), onInputFocus, onInputBlur }) {
|
||||||
// Day view: keep accordion calendar
|
// Day view: keep accordion calendar
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const y=selected.getFullYear(), m=selected.getMonth();
|
const y=selected.getFullYear(), m=selected.getMonth();
|
||||||
@@ -337,7 +337,7 @@ function MobileScheduleFilter({ selected, onMonthChange, view, eventTypes, filte
|
|||||||
Requires Availability
|
Requires Availability
|
||||||
</label>
|
</label>
|
||||||
{hasFilters && (
|
{hasFilters && (
|
||||||
<button onClick={()=>{onFilterKeyword('');onFilterTypeId('');onFilterAvailability(false);}} style={{fontSize:12,color:'var(--error)',background:'none',border:'none',cursor:'pointer',padding:0}}>✕ Clear all filters</button>
|
<button onClick={()=>{onFilterKeyword('');onFilterTypeId('');onFilterAvailability(false);onClearFromDate?.();}} style={{fontSize:12,color:'var(--error)',background:'none',border:'none',cursor:'pointer',padding:0}}>✕ Clear all filters</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -982,11 +982,21 @@ function expandEvents(events, rangeStart, rangeEnd) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse keyword string into match descriptors.
|
||||||
|
// Quoted terms ("mount") -> exact whole-word match only.
|
||||||
|
// Unquoted terms (mount) -> word-boundary prefix: term must start a word,
|
||||||
|
// so "mount" matches "mountain" but "mounte" does not.
|
||||||
function parseKeywords(raw) {
|
function parseKeywords(raw) {
|
||||||
const terms = [];
|
const terms = [];
|
||||||
const re = /"([^"]+)"|(\S+)/g;
|
const re = /"([^"]+)"|(\S+)/g;
|
||||||
let match;
|
let match;
|
||||||
while((match = re.exec(raw)) !== null) terms.push((match[1]||match[2]).toLowerCase());
|
while((match = re.exec(raw)) !== null) {
|
||||||
|
if (match[1] !== undefined) {
|
||||||
|
terms.push({ term: match[1].toLowerCase(), exact: true });
|
||||||
|
} else {
|
||||||
|
terms.push({ term: match[2].toLowerCase(), exact: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
return terms;
|
return terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,7 +1038,16 @@ function ScheduleView({ events, selectedDate, onSelect, filterKeyword='', filter
|
|||||||
if(filterAvailability && !e.track_availability) return false;
|
if(filterAvailability && !e.track_availability) return false;
|
||||||
if(terms.length>0) {
|
if(terms.length>0) {
|
||||||
const haystack=[e.title||'',e.location||'',e.description||''].join(' ').toLowerCase();
|
const haystack=[e.title||'',e.location||'',e.description||''].join(' ').toLowerCase();
|
||||||
if(!terms.some(t=>haystack.includes(t))) return false;
|
const matches = ({ term, exact }) => {
|
||||||
|
if (exact) {
|
||||||
|
// Quoted: whole-word match only — term must be surrounded by word boundaries
|
||||||
|
return new RegExp('\\b' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b').test(haystack);
|
||||||
|
} else {
|
||||||
|
// Unquoted: prefix-of-word match — term must appear at the start of a word
|
||||||
|
return new RegExp('\\b' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).test(haystack);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(!terms.some(matches)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -1460,7 +1479,7 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
|
|||||||
className="input"
|
className="input"
|
||||||
placeholder={`Keyword… (space = OR, "phrase")`}
|
placeholder={`Keyword… (space = OR, "phrase")`}
|
||||||
value={filterKeyword}
|
value={filterKeyword}
|
||||||
onChange={e => setFilterKeyword(e.target.value)} autoComplete="new-password" autoCorrect="off" autoCapitalize="off" spellCheck={false}
|
onChange={e => { setFilterKeyword(e.target.value); if (!e.target.value) setFilterFromDate(null); }} autoComplete="new-password" autoCorrect="off" autoCapitalize="off" spellCheck={false}
|
||||||
style={{ marginBottom:8, fontSize:13 }} />
|
style={{ marginBottom:8, fontSize:13 }} />
|
||||||
<select
|
<select
|
||||||
className="input"
|
className="input"
|
||||||
@@ -1530,11 +1549,12 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
|
|||||||
view={view}
|
view={view}
|
||||||
eventTypes={eventTypes}
|
eventTypes={eventTypes}
|
||||||
filterKeyword={filterKeyword}
|
filterKeyword={filterKeyword}
|
||||||
onFilterKeyword={setFilterKeyword}
|
onFilterKeyword={val => { setFilterKeyword(val); if (!val) setFilterFromDate(null); }}
|
||||||
filterTypeId={filterTypeId}
|
filterTypeId={filterTypeId}
|
||||||
onFilterTypeId={setFilterTypeId}
|
onFilterTypeId={setFilterTypeId}
|
||||||
filterAvailability={filterAvailability}
|
filterAvailability={filterAvailability}
|
||||||
onFilterAvailability={setFilterAvailability}
|
onFilterAvailability={setFilterAvailability}
|
||||||
|
onClearFromDate={() => setFilterFromDate(null)}
|
||||||
onInputFocus={()=>setInputFocused(true)}
|
onInputFocus={()=>setInputFocused(true)}
|
||||||
onInputBlur={()=>setInputFocused(false)}
|
onInputBlur={()=>setInputFocused(false)}
|
||||||
eventDates={eventDates}
|
eventDates={eventDates}
|
||||||
|
|||||||
Reference in New Issue
Block a user