mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
Room config
This commit is contained in:
86
server/migrations/versions/62dea3db63a5_add_room_options.py
Normal file
86
server/migrations/versions/62dea3db63a5_add_room_options.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
"""Add room options
|
||||||
|
|
||||||
|
Revision ID: 62dea3db63a5
|
||||||
|
Revises: 1340c04426b8
|
||||||
|
Create Date: 2024-09-03 16:19:26.861027
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "62dea3db63a5"
|
||||||
|
down_revision: Union[str, None] = "1340c04426b8"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column(
|
||||||
|
"meeting",
|
||||||
|
sa.Column(
|
||||||
|
"is_locked", sa.Boolean(), server_default=sa.text("0"), nullable=False
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"meeting",
|
||||||
|
sa.Column("room_mode", sa.String(), server_default="normal", nullable=False),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"meeting",
|
||||||
|
sa.Column(
|
||||||
|
"recording_type", sa.String(), server_default="cloud", nullable=False
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"meeting",
|
||||||
|
sa.Column(
|
||||||
|
"recording_trigger",
|
||||||
|
sa.String(),
|
||||||
|
server_default="automatic-2nd-participant",
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"room",
|
||||||
|
sa.Column(
|
||||||
|
"is_locked", sa.Boolean(), server_default=sa.text("0"), nullable=False
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"room",
|
||||||
|
sa.Column("room_mode", sa.String(), server_default="normal", nullable=False),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"room",
|
||||||
|
sa.Column(
|
||||||
|
"recording_type", sa.String(), server_default="cloud", nullable=False
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"room",
|
||||||
|
sa.Column(
|
||||||
|
"recording_trigger",
|
||||||
|
sa.String(),
|
||||||
|
server_default="automatic-2nd-participant",
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column("room", "recording_trigger")
|
||||||
|
op.drop_column("room", "recording_type")
|
||||||
|
op.drop_column("room", "room_mode")
|
||||||
|
op.drop_column("room", "is_locked")
|
||||||
|
op.drop_column("meeting", "recording_trigger")
|
||||||
|
op.drop_column("meeting", "recording_type")
|
||||||
|
op.drop_column("meeting", "room_mode")
|
||||||
|
op.drop_column("meeting", "is_locked")
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from reflector.db import database, metadata
|
from reflector.db import database, metadata
|
||||||
|
from reflector.db.rooms import Room
|
||||||
|
from sqlalchemy.sql import false
|
||||||
|
|
||||||
meetings = sqlalchemy.Table(
|
meetings = sqlalchemy.Table(
|
||||||
"meeting",
|
"meeting",
|
||||||
@@ -17,6 +20,21 @@ meetings = sqlalchemy.Table(
|
|||||||
sqlalchemy.Column("end_date", sqlalchemy.DateTime),
|
sqlalchemy.Column("end_date", sqlalchemy.DateTime),
|
||||||
sqlalchemy.Column("user_id", sqlalchemy.String),
|
sqlalchemy.Column("user_id", sqlalchemy.String),
|
||||||
sqlalchemy.Column("room_id", sqlalchemy.String),
|
sqlalchemy.Column("room_id", sqlalchemy.String),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"is_locked", sqlalchemy.Boolean, nullable=False, server_default=false()
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"room_mode", sqlalchemy.String, nullable=False, server_default="normal"
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"recording_type", sqlalchemy.String, nullable=False, server_default="cloud"
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"recording_trigger",
|
||||||
|
sqlalchemy.String,
|
||||||
|
nullable=False,
|
||||||
|
server_default="automatic-2nd-participant",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -30,6 +48,12 @@ class Meeting(BaseModel):
|
|||||||
end_date: datetime
|
end_date: datetime
|
||||||
user_id: str | None = None
|
user_id: str | None = None
|
||||||
room_id: str | None = None
|
room_id: str | None = None
|
||||||
|
is_locked: bool = False
|
||||||
|
room_mode: Literal["normal", "group"] = "normal"
|
||||||
|
recording_type: Literal["none", "local", "cloud"] = "cloud"
|
||||||
|
recording_trigger: Literal[
|
||||||
|
"none", "prompt", "automatic", "automatic-2nd-participant"
|
||||||
|
] = "automatic-2nd-participant"
|
||||||
|
|
||||||
|
|
||||||
class MeetingController:
|
class MeetingController:
|
||||||
@@ -43,7 +67,7 @@ class MeetingController:
|
|||||||
start_date: datetime,
|
start_date: datetime,
|
||||||
end_date: datetime,
|
end_date: datetime,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
room_id: str = None,
|
room: Room,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Create a new meeting
|
Create a new meeting
|
||||||
@@ -57,7 +81,11 @@ class MeetingController:
|
|||||||
start_date=start_date,
|
start_date=start_date,
|
||||||
end_date=end_date,
|
end_date=end_date,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
room_id=room_id,
|
room_id=room.id,
|
||||||
|
is_locked=room.is_locked,
|
||||||
|
room_mode=room.room_mode,
|
||||||
|
recording_type=room.recording_type,
|
||||||
|
recording_trigger=room.recording_trigger,
|
||||||
)
|
)
|
||||||
query = meetings.insert().values(**meeting.model_dump())
|
query = meetings.insert().values(**meeting.model_dump())
|
||||||
await database.execute(query)
|
await database.execute(query)
|
||||||
@@ -77,15 +105,23 @@ class MeetingController:
|
|||||||
|
|
||||||
return Meeting(**result)
|
return Meeting(**result)
|
||||||
|
|
||||||
async def get_latest(self, room_id: str) -> Meeting:
|
async def get_latest(self, room: Room) -> Meeting:
|
||||||
"""
|
"""
|
||||||
Get latest meeting for a room.
|
Get latest meeting for a room.
|
||||||
"""
|
"""
|
||||||
end_date = getattr(meetings.c, "end_date")
|
end_date = getattr(meetings.c, "end_date")
|
||||||
query = (
|
query = (
|
||||||
meetings.select()
|
meetings.select()
|
||||||
.where(meetings.c.room_id == room_id)
|
.where(
|
||||||
.where(meetings.c.end_date > datetime.now(timezone.utc))
|
sqlalchemy.and_(
|
||||||
|
meetings.c.room_id == room.id,
|
||||||
|
meetings.c.is_locked == room.is_locked,
|
||||||
|
meetings.c.room_mode == room.room_mode,
|
||||||
|
meetings.c.recording_type == room.recording_type,
|
||||||
|
meetings.c.recording_trigger == room.recording_trigger,
|
||||||
|
meetings.c.end_date > datetime.now(timezone.utc),
|
||||||
|
)
|
||||||
|
)
|
||||||
.order_by(end_date.desc())
|
.order_by(end_date.desc())
|
||||||
)
|
)
|
||||||
result = await database.fetch_one(query)
|
result = await database.fetch_one(query)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
@@ -19,6 +20,21 @@ rooms = sqlalchemy.Table(
|
|||||||
),
|
),
|
||||||
sqlalchemy.Column("zulip_stream", sqlalchemy.String),
|
sqlalchemy.Column("zulip_stream", sqlalchemy.String),
|
||||||
sqlalchemy.Column("zulip_topic", sqlalchemy.String),
|
sqlalchemy.Column("zulip_topic", sqlalchemy.String),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"is_locked", sqlalchemy.Boolean, nullable=False, server_default=false()
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"room_mode", sqlalchemy.String, nullable=False, server_default="normal"
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"recording_type", sqlalchemy.String, nullable=False, server_default="cloud"
|
||||||
|
),
|
||||||
|
sqlalchemy.Column(
|
||||||
|
"recording_trigger",
|
||||||
|
sqlalchemy.String,
|
||||||
|
nullable=False,
|
||||||
|
server_default="automatic-2nd-participant",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -30,6 +46,12 @@ class Room(BaseModel):
|
|||||||
zulip_auto_post: bool = False
|
zulip_auto_post: bool = False
|
||||||
zulip_stream: str = ""
|
zulip_stream: str = ""
|
||||||
zulip_topic: str = ""
|
zulip_topic: str = ""
|
||||||
|
is_locked: bool = False
|
||||||
|
room_mode: Literal["normal", "group"] = "normal"
|
||||||
|
recording_type: Literal["none", "local", "cloud"] = "cloud"
|
||||||
|
recording_trigger: Literal[
|
||||||
|
"none", "prompt", "automatic", "automatic-2nd-participant"
|
||||||
|
] = "automatic-2nd-participant"
|
||||||
|
|
||||||
|
|
||||||
class RoomController:
|
class RoomController:
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ class Room(BaseModel):
|
|||||||
zulip_auto_post: bool
|
zulip_auto_post: bool
|
||||||
zulip_stream: str
|
zulip_stream: str
|
||||||
zulip_topic: str
|
zulip_topic: str
|
||||||
|
is_locked: bool
|
||||||
|
room_mode: str
|
||||||
|
recording_type: str
|
||||||
|
recording_trigger: str
|
||||||
|
|
||||||
|
|
||||||
class Meeting(BaseModel):
|
class Meeting(BaseModel):
|
||||||
@@ -41,6 +45,10 @@ class CreateRoom(BaseModel):
|
|||||||
zulip_auto_post: bool
|
zulip_auto_post: bool
|
||||||
zulip_stream: str
|
zulip_stream: str
|
||||||
zulip_topic: str
|
zulip_topic: str
|
||||||
|
is_locked: bool
|
||||||
|
room_mode: str
|
||||||
|
recording_type: str
|
||||||
|
recording_trigger: str
|
||||||
|
|
||||||
|
|
||||||
class UpdateRoom(BaseModel):
|
class UpdateRoom(BaseModel):
|
||||||
@@ -48,6 +56,10 @@ class UpdateRoom(BaseModel):
|
|||||||
zulip_auto_post: bool
|
zulip_auto_post: bool
|
||||||
zulip_stream: str
|
zulip_stream: str
|
||||||
zulip_topic: str
|
zulip_topic: str
|
||||||
|
is_locked: bool
|
||||||
|
room_mode: str
|
||||||
|
recording_type: str
|
||||||
|
recording_trigger: str
|
||||||
|
|
||||||
|
|
||||||
class DeletionStatus(BaseModel):
|
class DeletionStatus(BaseModel):
|
||||||
@@ -126,11 +138,13 @@ async def rooms_create_meeting(
|
|||||||
if not room:
|
if not room:
|
||||||
raise HTTPException(status_code=404, detail="Room not found")
|
raise HTTPException(status_code=404, detail="Room not found")
|
||||||
|
|
||||||
meeting = await meetings_controller.get_latest(room_id=room.id)
|
meeting = await meetings_controller.get_latest(room=room)
|
||||||
if meeting is None:
|
if meeting is None:
|
||||||
start_date = datetime.now(timezone.utc)
|
start_date = datetime.now(timezone.utc)
|
||||||
end_date = start_date + timedelta(hours=1)
|
end_date = start_date + timedelta(hours=1)
|
||||||
meeting = await create_meeting("", start_date=start_date, end_date=end_date)
|
meeting = await create_meeting(
|
||||||
|
"", start_date=start_date, end_date=end_date, room=room
|
||||||
|
)
|
||||||
|
|
||||||
meeting = await meetings_controller.create(
|
meeting = await meetings_controller.create(
|
||||||
id=meeting["meetingId"],
|
id=meeting["meetingId"],
|
||||||
@@ -141,7 +155,10 @@ async def rooms_create_meeting(
|
|||||||
start_date=datetime.fromisoformat(meeting["startDate"]),
|
start_date=datetime.fromisoformat(meeting["startDate"]),
|
||||||
end_date=datetime.fromisoformat(meeting["endDate"]),
|
end_date=datetime.fromisoformat(meeting["endDate"]),
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
room_id=room.id,
|
room=room,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if user_id is None:
|
||||||
|
meeting.host_room_url = ""
|
||||||
|
|
||||||
return meeting
|
return meeting
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
from reflector.db.rooms import Room
|
||||||
from reflector.settings import settings
|
from reflector.settings import settings
|
||||||
|
|
||||||
|
|
||||||
async def create_meeting(
|
async def create_meeting(
|
||||||
room_name_prefix: str, start_date: datetime, end_date: datetime
|
room_name_prefix: str, start_date: datetime, end_date: datetime, room: Room
|
||||||
):
|
):
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
@@ -13,14 +14,14 @@ async def create_meeting(
|
|||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
"templateType": "viewerMode",
|
"templateType": "viewerMode",
|
||||||
"isLocked": False,
|
"isLocked": room.is_locked,
|
||||||
"roomNamePrefix": room_name_prefix,
|
"roomNamePrefix": room_name_prefix,
|
||||||
"roomNamePattern": "uuid",
|
"roomNamePattern": "uuid",
|
||||||
"roomMode": "normal",
|
"roomMode": room.room_mode,
|
||||||
"startDate": start_date.isoformat(),
|
"startDate": start_date.isoformat(),
|
||||||
"endDate": end_date.isoformat(),
|
"endDate": end_date.isoformat(),
|
||||||
"recording": {
|
"recording": {
|
||||||
"type": "cloud",
|
"type": room.recording_type,
|
||||||
"destination": {
|
"destination": {
|
||||||
"provider": "s3",
|
"provider": "s3",
|
||||||
"bucket": settings.AWS_WHEREBY_S3_BUCKET,
|
"bucket": settings.AWS_WHEREBY_S3_BUCKET,
|
||||||
@@ -28,7 +29,7 @@ async def create_meeting(
|
|||||||
"accessKeySecret": settings.AWS_WHEREBY_ACCESS_KEY_SECRET,
|
"accessKeySecret": settings.AWS_WHEREBY_ACCESS_KEY_SECRET,
|
||||||
"fileFormat": "mp4",
|
"fileFormat": "mp4",
|
||||||
},
|
},
|
||||||
"startTrigger": "automatic-2nd-participant",
|
"startTrigger": room.recording_trigger,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { Container } from "@chakra-ui/react";
|
import { Container } from "@chakra-ui/react";
|
||||||
import { FaEllipsisVertical, FaTrash, FaPencil } from "react-icons/fa6";
|
import { FaEllipsisVertical, FaTrash, FaPencil, FaLink } from "react-icons/fa6";
|
||||||
import useApi from "../../lib/useApi";
|
import useApi from "../../lib/useApi";
|
||||||
import useRoomList from "./useRoomList";
|
import useRoomList from "./useRoomList";
|
||||||
import { DomainContext } from "../../domainContext";
|
import { DomainContext } from "../../domainContext";
|
||||||
@@ -51,14 +51,31 @@ interface SelectOption extends OptionBase {
|
|||||||
|
|
||||||
const RESERVED_PATHS = ["browse", "rooms", "transcripts"];
|
const RESERVED_PATHS = ["browse", "rooms", "transcripts"];
|
||||||
|
|
||||||
|
const roomModeOptions: Options<SelectOption> = [
|
||||||
|
{ label: "2-4 people", value: "normal" },
|
||||||
|
{ label: "2-200 people", value: "group" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const recordingTriggerOptions: Options<SelectOption> = [
|
||||||
|
{ label: "None", value: "none" },
|
||||||
|
{ label: "Prompt", value: "prompt" },
|
||||||
|
{ label: "Automatic", value: "automatic-2nd-participant" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const roomInitialState = {
|
||||||
|
name: "",
|
||||||
|
zulipAutoPost: false,
|
||||||
|
zulipStream: "",
|
||||||
|
zulipTopic: "",
|
||||||
|
isLocked: false,
|
||||||
|
roomMode: "normal",
|
||||||
|
recordingType: "cloud",
|
||||||
|
recordingTrigger: "none",
|
||||||
|
};
|
||||||
|
|
||||||
export default function RoomsList() {
|
export default function RoomsList() {
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const [room, setRoom] = useState({
|
const [room, setRoom] = useState(roomInitialState);
|
||||||
name: "",
|
|
||||||
zulipAutoPost: false,
|
|
||||||
zulipStream: "",
|
|
||||||
zulipTopic: "",
|
|
||||||
});
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [editRoomId, setEditRoomId] = useState("");
|
const [editRoomId, setEditRoomId] = useState("");
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
@@ -66,6 +83,7 @@ export default function RoomsList() {
|
|||||||
const { loading, response, refetch } = useRoomList(page);
|
const { loading, response, refetch } = useRoomList(page);
|
||||||
const [streams, setStreams] = useState<Stream[]>([]);
|
const [streams, setStreams] = useState<Stream[]>([]);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
const [linkCopied, setLinkCopied] = useState("");
|
||||||
|
|
||||||
const { zulip_streams } = useContext(DomainContext);
|
const { zulip_streams } = useContext(DomainContext);
|
||||||
|
|
||||||
@@ -100,6 +118,16 @@ export default function RoomsList() {
|
|||||||
.find((stream) => stream.name === room.zulipStream)
|
.find((stream) => stream.name === room.zulipStream)
|
||||||
?.topics.map((topic) => ({ label: topic, value: topic })) || [];
|
?.topics.map((topic) => ({ label: topic, value: topic })) || [];
|
||||||
|
|
||||||
|
const handleCopyUrl = (roomName: string) => {
|
||||||
|
const roomUrl = `${window.location.origin}/${roomName}`;
|
||||||
|
navigator.clipboard.writeText(roomUrl);
|
||||||
|
setLinkCopied(roomName);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setLinkCopied("");
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSaveRoom = async () => {
|
const handleSaveRoom = async () => {
|
||||||
try {
|
try {
|
||||||
if (RESERVED_PATHS.includes(room.name)) {
|
if (RESERVED_PATHS.includes(room.name)) {
|
||||||
@@ -107,32 +135,29 @@ export default function RoomsList() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const roomData = {
|
||||||
|
name: room.name,
|
||||||
|
zulip_auto_post: room.zulipAutoPost,
|
||||||
|
zulip_stream: room.zulipStream,
|
||||||
|
zulip_topic: room.zulipTopic,
|
||||||
|
is_locked: room.isLocked,
|
||||||
|
room_mode: room.roomMode,
|
||||||
|
recording_type: room.recordingType,
|
||||||
|
recording_trigger: room.recordingTrigger,
|
||||||
|
};
|
||||||
|
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
await api?.v1RoomsUpdate({
|
await api?.v1RoomsUpdate({
|
||||||
roomId: editRoomId,
|
roomId: editRoomId,
|
||||||
requestBody: {
|
requestBody: roomData,
|
||||||
name: room.name,
|
|
||||||
zulip_auto_post: room.zulipAutoPost,
|
|
||||||
zulip_stream: room.zulipStream,
|
|
||||||
zulip_topic: room.zulipTopic,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await api?.v1RoomsCreate({
|
await api?.v1RoomsCreate({
|
||||||
requestBody: {
|
requestBody: roomData,
|
||||||
name: room.name,
|
|
||||||
zulip_auto_post: room.zulipAutoPost,
|
|
||||||
zulip_stream: room.zulipStream,
|
|
||||||
zulip_topic: room.zulipTopic,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setRoom({
|
|
||||||
name: "",
|
setRoom(roomInitialState);
|
||||||
zulipAutoPost: false,
|
|
||||||
zulipStream: "",
|
|
||||||
zulipTopic: "",
|
|
||||||
});
|
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
setEditRoomId("");
|
setEditRoomId("");
|
||||||
setError("");
|
setError("");
|
||||||
@@ -149,6 +174,10 @@ export default function RoomsList() {
|
|||||||
zulipAutoPost: roomData.zulip_auto_post,
|
zulipAutoPost: roomData.zulip_auto_post,
|
||||||
zulipStream: roomData.zulip_stream,
|
zulipStream: roomData.zulip_stream,
|
||||||
zulipTopic: roomData.zulip_topic,
|
zulipTopic: roomData.zulip_topic,
|
||||||
|
isLocked: roomData.is_locked,
|
||||||
|
roomMode: roomData.room_mode,
|
||||||
|
recordingType: roomData.recording_type,
|
||||||
|
recordingTrigger: roomData.recording_trigger,
|
||||||
});
|
});
|
||||||
setEditRoomId(roomId);
|
setEditRoomId(roomId);
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
@@ -204,12 +233,7 @@ export default function RoomsList() {
|
|||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
setRoom({
|
setRoom(roomInitialState);
|
||||||
name: "",
|
|
||||||
zulipAutoPost: false,
|
|
||||||
zulipStream: "",
|
|
||||||
zulipTopic: "",
|
|
||||||
});
|
|
||||||
setError("");
|
setError("");
|
||||||
onOpen();
|
onOpen();
|
||||||
}}
|
}}
|
||||||
@@ -236,6 +260,53 @@ export default function RoomsList() {
|
|||||||
{error && <Text color="red.500">{error}</Text>}
|
{error && <Text color="red.500">{error}</Text>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
|
<FormControl mt={4}>
|
||||||
|
<Checkbox
|
||||||
|
name="isLocked"
|
||||||
|
isChecked={room.isLocked}
|
||||||
|
onChange={handleRoomChange}
|
||||||
|
>
|
||||||
|
Locked room
|
||||||
|
</Checkbox>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl mt={4}>
|
||||||
|
<FormLabel>Room size</FormLabel>
|
||||||
|
<Select
|
||||||
|
name="roomMode"
|
||||||
|
options={roomModeOptions}
|
||||||
|
value={{
|
||||||
|
label: roomModeOptions.find(
|
||||||
|
(rm) => rm.value === room.roomMode,
|
||||||
|
)?.label,
|
||||||
|
value: room.roomMode,
|
||||||
|
}}
|
||||||
|
onChange={(newValue) =>
|
||||||
|
setRoom({
|
||||||
|
...room,
|
||||||
|
roomMode: newValue!.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl mt={4}>
|
||||||
|
<FormLabel>Recording start trigger</FormLabel>
|
||||||
|
<Select
|
||||||
|
name="recordingTrigger"
|
||||||
|
options={recordingTriggerOptions}
|
||||||
|
value={{
|
||||||
|
label: recordingTriggerOptions.find(
|
||||||
|
(rt) => rt.value === room.recordingTrigger,
|
||||||
|
)?.label,
|
||||||
|
value: room.recordingTrigger,
|
||||||
|
}}
|
||||||
|
onChange={(newValue) =>
|
||||||
|
setRoom({
|
||||||
|
...room,
|
||||||
|
recordingTrigger: newValue!.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
<FormControl mt={8}>
|
<FormControl mt={8}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="zulipAutoPost"
|
name="zulipAutoPost"
|
||||||
@@ -309,6 +380,19 @@ export default function RoomsList() {
|
|||||||
<Link href={`/${roomData.name}`}>{roomData.name}</Link>
|
<Link href={`/${roomData.name}`}>{roomData.name}</Link>
|
||||||
</Heading>
|
</Heading>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
|
{linkCopied === roomData.name ? (
|
||||||
|
<Text mr={2} color="green.500">
|
||||||
|
Link copied!
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<IconButton
|
||||||
|
aria-label="Copy URL"
|
||||||
|
icon={<FaLink />}
|
||||||
|
onClick={() => handleCopyUrl(roomData.name)}
|
||||||
|
mr={2}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Menu closeOnSelect={true}>
|
<Menu closeOnSelect={true}>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={IconButton}
|
as={IconButton}
|
||||||
|
|||||||
@@ -71,9 +71,34 @@ export const $CreateRoom = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
title: "Zulip Topic",
|
title: "Zulip Topic",
|
||||||
},
|
},
|
||||||
|
is_locked: {
|
||||||
|
type: "boolean",
|
||||||
|
title: "Is Locked",
|
||||||
|
},
|
||||||
|
room_mode: {
|
||||||
|
type: "string",
|
||||||
|
title: "Room Mode",
|
||||||
|
},
|
||||||
|
recording_type: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Type",
|
||||||
|
},
|
||||||
|
recording_trigger: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Trigger",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["name", "zulip_auto_post", "zulip_stream", "zulip_topic"],
|
required: [
|
||||||
|
"name",
|
||||||
|
"zulip_auto_post",
|
||||||
|
"zulip_stream",
|
||||||
|
"zulip_topic",
|
||||||
|
"is_locked",
|
||||||
|
"room_mode",
|
||||||
|
"recording_type",
|
||||||
|
"recording_trigger",
|
||||||
|
],
|
||||||
title: "CreateRoom",
|
title: "CreateRoom",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@@ -667,6 +692,22 @@ export const $Room = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
title: "Zulip Topic",
|
title: "Zulip Topic",
|
||||||
},
|
},
|
||||||
|
is_locked: {
|
||||||
|
type: "boolean",
|
||||||
|
title: "Is Locked",
|
||||||
|
},
|
||||||
|
room_mode: {
|
||||||
|
type: "string",
|
||||||
|
title: "Room Mode",
|
||||||
|
},
|
||||||
|
recording_type: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Type",
|
||||||
|
},
|
||||||
|
recording_trigger: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Trigger",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
type: "object",
|
type: "object",
|
||||||
required: [
|
required: [
|
||||||
@@ -677,6 +718,10 @@ export const $Room = {
|
|||||||
"zulip_auto_post",
|
"zulip_auto_post",
|
||||||
"zulip_stream",
|
"zulip_stream",
|
||||||
"zulip_topic",
|
"zulip_topic",
|
||||||
|
"is_locked",
|
||||||
|
"room_mode",
|
||||||
|
"recording_type",
|
||||||
|
"recording_trigger",
|
||||||
],
|
],
|
||||||
title: "Room",
|
title: "Room",
|
||||||
} as const;
|
} as const;
|
||||||
@@ -857,9 +902,34 @@ export const $UpdateRoom = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
title: "Zulip Topic",
|
title: "Zulip Topic",
|
||||||
},
|
},
|
||||||
|
is_locked: {
|
||||||
|
type: "boolean",
|
||||||
|
title: "Is Locked",
|
||||||
|
},
|
||||||
|
room_mode: {
|
||||||
|
type: "string",
|
||||||
|
title: "Room Mode",
|
||||||
|
},
|
||||||
|
recording_type: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Type",
|
||||||
|
},
|
||||||
|
recording_trigger: {
|
||||||
|
type: "string",
|
||||||
|
title: "Recording Trigger",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["name", "zulip_auto_post", "zulip_stream", "zulip_topic"],
|
required: [
|
||||||
|
"name",
|
||||||
|
"zulip_auto_post",
|
||||||
|
"zulip_stream",
|
||||||
|
"zulip_topic",
|
||||||
|
"is_locked",
|
||||||
|
"room_mode",
|
||||||
|
"recording_type",
|
||||||
|
"recording_trigger",
|
||||||
|
],
|
||||||
title: "UpdateRoom",
|
title: "UpdateRoom",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ export type CreateRoom = {
|
|||||||
zulip_auto_post: boolean;
|
zulip_auto_post: boolean;
|
||||||
zulip_stream: string;
|
zulip_stream: string;
|
||||||
zulip_topic: string;
|
zulip_topic: string;
|
||||||
|
is_locked: boolean;
|
||||||
|
room_mode: string;
|
||||||
|
recording_type: string;
|
||||||
|
recording_trigger: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CreateTranscript = {
|
export type CreateTranscript = {
|
||||||
@@ -132,6 +136,10 @@ export type Room = {
|
|||||||
zulip_auto_post: boolean;
|
zulip_auto_post: boolean;
|
||||||
zulip_stream: string;
|
zulip_stream: string;
|
||||||
zulip_topic: string;
|
zulip_topic: string;
|
||||||
|
is_locked: boolean;
|
||||||
|
room_mode: string;
|
||||||
|
recording_type: string;
|
||||||
|
recording_trigger: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RtcOffer = {
|
export type RtcOffer = {
|
||||||
@@ -176,6 +184,10 @@ export type UpdateRoom = {
|
|||||||
zulip_auto_post: boolean;
|
zulip_auto_post: boolean;
|
||||||
zulip_stream: string;
|
zulip_stream: string;
|
||||||
zulip_topic: string;
|
zulip_topic: string;
|
||||||
|
is_locked: boolean;
|
||||||
|
room_mode: string;
|
||||||
|
recording_type: string;
|
||||||
|
recording_trigger: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateTranscript = {
|
export type UpdateTranscript = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
|
experimental: { esmExternals: "loose" },
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user