v0.12.13 user manager permissions + member event calendar

This commit is contained in:
2026-03-24 07:57:03 -04:00
parent 2e3e4100f5
commit 44799f76cc
7 changed files with 9 additions and 8 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "rosterchirp-backend", "name": "rosterchirp-backend",
"version": "0.12.12", "version": "0.12.13",
"description": "RosterChirp backend server", "description": "RosterChirp backend server",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {

View File

@@ -39,7 +39,7 @@ function adminMiddleware(req, res, next) {
} }
async function teamManagerMiddleware(req, res, next) { async function teamManagerMiddleware(req, res, next) {
if (req.user?.role === 'admin') return next(); if (req.user?.role === 'admin' || req.user?.role === 'manager') return next();
try { try {
const tmSetting = await queryOne(req.schema, const tmSetting = await queryOne(req.schema,
"SELECT value FROM settings WHERE key = 'team_tool_managers'" "SELECT value FROM settings WHERE key = 'team_tool_managers'"

View File

@@ -54,7 +54,7 @@ async function postEventNotification(schema, eventId, actorId, isUpdate) {
// ── Helpers ─────────────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────────────
async function isToolManagerFn(schema, user) { async function isToolManagerFn(schema, user) {
if (user.role === 'admin') return true; if (user.role === 'admin' || user.role === 'manager') return true;
const tm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_tool_managers'"); const tm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_tool_managers'");
const gm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_group_managers'"); const gm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_group_managers'");
const groupIds = [...new Set([...JSON.parse(tm?.value||'[]'), ...JSON.parse(gm?.value||'[]')])]; const groupIds = [...new Set([...JSON.parse(tm?.value||'[]'), ...JSON.parse(gm?.value||'[]')])];

View File

@@ -13,7 +13,7 @@
# ───────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────
set -euo pipefail set -euo pipefail
VERSION="${1:-0.12.12}" VERSION="${1:-0.12.13}"
ACTION="${2:-}" ACTION="${2:-}"
REGISTRY="${REGISTRY:-}" REGISTRY="${REGISTRY:-}"
IMAGE_NAME="rosterchirp" IMAGE_NAME="rosterchirp"

View File

@@ -1,6 +1,6 @@
{ {
"name": "rosterchirp-frontend", "name": "rosterchirp-frontend",
"version": "0.12.12", "version": "0.12.13",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1364,10 +1364,11 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
const createRef = useRef(null); const createRef = useRef(null);
const load = useCallback(() => { const load = useCallback(() => {
Promise.all([api.getEvents(), api.getEventTypes(), api.getUserGroups()]) const ugPromise = isToolManager ? api.getUserGroups() : Promise.resolve({ groups: [] });
Promise.all([api.getEvents(), api.getEventTypes(), ugPromise])
.then(([ev,et,ug]) => { setEvents(ev.events||[]); setEventTypes(et.eventTypes||[]); setUserGroups(ug.groups||[]); setLoading(false); }) .then(([ev,et,ug]) => { setEvents(ev.events||[]); setEventTypes(et.eventTypes||[]); setUserGroups(ug.groups||[]); setLoading(false); })
.catch(() => setLoading(false)); .catch(() => setLoading(false));
}, []); }, [isToolManager]);
useEffect(() => { load(); }, [load]); useEffect(() => { load(); }, [load]);

View File

@@ -393,7 +393,7 @@ export default function Chat() {
...(groups.privateGroups || []) ...(groups.privateGroups || [])
].find(g => g.id === activeGroupId); ].find(g => g.id === activeGroupId);
const isToolManager = user?.role === 'admin' || (features.teamToolManagers || []).some(gid => (features.userGroupMemberships || []).includes(gid)); const isToolManager = user?.role === 'admin' || user?.role === 'manager' || (features.teamToolManagers || []).some(gid => (features.userGroupMemberships || []).includes(gid));
// Unread indicators for burger icon and nav drawer // Unread indicators for burger icon and nav drawer
const allGroupsFlat = [...(groups.publicGroups || []), ...(groups.privateGroups || [])]; const allGroupsFlat = [...(groups.publicGroups || []), ...(groups.privateGroups || [])];