diff --git a/backend/package.json b/backend/package.json index 1df4df5..a7e4f7a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-backend", - "version": "0.12.9", + "version": "0.12.10", "description": "RosterChirp backend server", "main": "src/index.js", "scripts": { diff --git a/build.sh b/build.sh index 4ff347c..4f58bd5 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.12.9}" +VERSION="${1:-0.12.10}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="rosterchirp" diff --git a/frontend/package.json b/frontend/package.json index 7a5eb47..18528db 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-frontend", - "version": "0.12.9", + "version": "0.12.10", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/pages/GroupManagerPage.jsx b/frontend/src/pages/GroupManagerPage.jsx index 9b534b9..b9a4cc4 100644 --- a/frontend/src/pages/GroupManagerPage.jsx +++ b/frontend/src/pages/GroupManagerPage.jsx @@ -21,7 +21,9 @@ import Avatar from '../components/Avatar.jsx'; function UserCheckList({ allUsers, selectedIds, onChange, onIF, onIB }) { const [search, setSearch] = useState(''); - const filtered = allUsers.filter(u => (u.display_name||u.name).toLowerCase().includes(search.toLowerCase())); + const filtered = allUsers + .filter(u => (u.display_name||u.name).toLowerCase().includes(search.toLowerCase())) + .sort((a, b) => (a.display_name||a.name).localeCompare(b.display_name||b.name)); return (
setSearch(e.target.value)} autoComplete="new-password" style={{ marginBottom:8 }} autoComplete="new-password" onFocus={onIF} onBlur={onIB} /> diff --git a/frontend/src/pages/UserManagerPage.jsx b/frontend/src/pages/UserManagerPage.jsx index 9e8abc0..42824ba 100644 --- a/frontend/src/pages/UserManagerPage.jsx +++ b/frontend/src/pages/UserManagerPage.jsx @@ -356,33 +356,47 @@ export default function UserManagerPage({ isMobile = false, onProfile, onHelp, o )} {/* Content */} -
+
{tab === 'users' && ( <> - setSearch(e.target.value)} - onFocus={onIF} onBlur={onIB} - autoComplete="new-password" autoCorrect="off" spellCheck={false} - style={{ marginBottom:16, width:'100%', maxWidth: isMobile ? '100%' : 400 }} /> -
- {loading ? ( -
- ) : loadError ? ( -
-
⚠ {loadError}
- -
- ) : filtered.length === 0 ? ( -
- {search ? 'No users match your search.' : 'No users yet.'} -
- ) : ( - filtered.map(u => ) - )} + {/* Search — always visible, outside scroll area */} +
+ setSearch(e.target.value)} + onFocus={onIF} onBlur={onIB} + autoComplete="new-password" autoCorrect="off" spellCheck={false} + style={{ width:'100%', maxWidth: isMobile ? '100%' : 400 }} /> +
+ {/* User list — bounded scroll */} +
+
+ {loading ? ( +
+ ) : loadError ? ( +
+
⚠ {loadError}
+ +
+ ) : filtered.length === 0 ? ( +
+ {search ? 'No users match your search.' : 'No users yet.'} +
+ ) : ( + filtered.map(u => ) + )} +
)} - {tab === 'create' && { load(); setTab('users'); }} isMobile={isMobile} onIF={onIF} onIB={onIB} />} - {tab === 'bulk' && } + {tab === 'create' && ( +
+ { load(); setTab('users'); }} isMobile={isMobile} onIF={onIF} onIB={onIB} /> +
+ )} + {tab === 'bulk' && ( +
+ +
+ )}
{/* Mobile footer — fixed, hidden when any input is focused (keyboard open) */}