feat: reorganize room edit dialog and fix Force Sync button

- Move WebHook configuration from General to dedicated WebHook tab
- Add WebHook tab after Share tab in room edit dialog
- Fix Force Sync button not appearing by adding missing isEditing prop
- Fix indentation issues in MeetingSelection component

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-08 19:41:57 -06:00
parent f15e1dc7f7
commit 7193b4dbba
21 changed files with 1053 additions and 1551 deletions

View File

@@ -10,6 +10,7 @@ from reflector.db.meetings import (
meeting_consent_controller,
meetings_controller,
)
from reflector.db.rooms import rooms_controller
router = APIRouter()
@@ -41,3 +42,38 @@ async def meeting_audio_consent(
updated_consent = await meeting_consent_controller.upsert(consent)
return {"status": "success", "consent_id": updated_consent.id}
@router.patch("/meetings/{meeting_id}/deactivate")
async def meeting_deactivate(
meeting_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
"""Deactivate a meeting (owner only)"""
meeting = await meetings_controller.get_by_id(meeting_id)
if not meeting:
raise HTTPException(status_code=404, detail="Meeting not found")
if not meeting.is_active:
raise HTTPException(status_code=400, detail="Meeting is already inactive")
# Check if user is the meeting owner or room owner
user_id = user["sub"] if user else None
if not user_id:
raise HTTPException(status_code=401, detail="Authentication required")
# Get room to check ownership
room = await rooms_controller.get_by_id(meeting.room_id)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
# Only room owner or meeting creator can deactivate
if user_id != room.user_id and user_id != meeting.user_id:
raise HTTPException(
status_code=403, detail="Only the room owner can deactivate meetings"
)
# Deactivate the meeting
await meetings_controller.update_meeting(meeting_id, is_active=False)
return {"status": "success", "meeting_id": meeting_id}

View File

@@ -19,7 +19,7 @@ ATTENDEE;CN=Mathieu Virbel;PARTSTAT=ACCEPTED:MAILTO:mathieu@monadical.com
DTEND;TZID=America/Costa_Rica:20250819T143000
DTSTAMP:20250819T155951Z
DTSTART;TZID=America/Costa_Rica:20250819T140000
LOCATION:http://localhost:1250/room/mathieu
LOCATION:http://localhost:1250/mathieu
ORGANIZER;CN=Mathieu Virbel:MAILTO:mathieu@monadical.com
SEQUENCE:1
SUMMARY:Checkin

View File

@@ -9,7 +9,7 @@ ATTENDEE:MAILTO:alice@example.com,bob@example.com,charlie@example.com,diana@exam
DTEND:20250819T190000Z
DTSTAMP:20250819T174000Z
DTSTART:20250819T180000Z
LOCATION:http://localhost:1250/room/test-room
LOCATION:http://localhost:1250/test-room
ORGANIZER;CN=Test Organizer:MAILTO:organizer@example.com
SEQUENCE:1
SUMMARY:Test Meeting with Many Attendees

View File

@@ -51,7 +51,7 @@ async def test_attendee_parsing_bug():
calendar = sync_service.fetch_service.parse_ics(ics_content)
from reflector.settings import settings
room_url = f"{settings.BASE_URL}/room/{room.name}"
room_url = f"{settings.BASE_URL}/{room.name}"
print(f"Room URL being used for matching: {room_url}")
print(f"ICS content:\n{ics_content}")

View File

@@ -36,7 +36,7 @@ async def test_calendar_event_create():
description="Weekly team sync",
start_time=now + timedelta(hours=1),
end_time=now + timedelta(hours=2),
location=f"https://example.com/room/{room.name}",
location=f"https://example.com/{room.name}",
attendees=[
{"email": "alice@example.com", "name": "Alice", "status": "ACCEPTED"},
{"email": "bob@example.com", "name": "Bob", "status": "TENTATIVE"},

View File

@@ -108,7 +108,7 @@ async def test_trigger_ics_sync(authenticated_client):
event.add("summary", "API Test Meeting")
from reflector.settings import settings
event.add("location", f"{settings.BASE_URL}/room/{room.name}")
event.add("location", f"{settings.BASE_URL}/{room.name}")
now = datetime.now(timezone.utc)
event.add("dtstart", now + timedelta(hours=1))
event.add("dtend", now + timedelta(hours=2))