diff --git a/src/frontend/src/features/recording/components/ControlsButton.tsx b/src/frontend/src/features/recording/components/ControlsButton.tsx
index 6b31c593..f719d5bb 100644
--- a/src/frontend/src/features/recording/components/ControlsButton.tsx
+++ b/src/frontend/src/features/recording/components/ControlsButton.tsx
@@ -1,4 +1,4 @@
-import { css } from '@/styled-system/css'
+import { css, cx } from '@/styled-system/css'
import { HStack } from '@/styled-system/jsx'
import { Spinner } from '@/primitives/Spinner'
import { Button, Text } from '@/primitives'
@@ -7,6 +7,8 @@ import { RecordingStatuses } from '../hooks/useRecordingStatuses'
import { ReactNode, useEffect, useRef, useState } from 'react'
import { useRoomContext } from '@livekit/components-react'
import { ConnectionState } from 'livekit-client'
+import { Button as RACButton } from 'react-aria-components'
+import { parseLineBreaks } from '@/utils/parseLineBreaks'
const Layout = ({ children }: { children: ReactNode }) => (
void
isPendingToStart: boolean
isPendingToStop: boolean
+ openSidePanel: () => void
}
const MIN_SPINNER_DISPLAY_TIME = 2000
@@ -35,6 +38,7 @@ export const ControlsButton = ({
handle,
isPendingToStart,
isPendingToStop,
+ openSidePanel,
}: ControlsButtonProps) => {
const { t } = useTranslation('rooms', { keyPrefix: i18nKeyPrefix })
@@ -45,7 +49,7 @@ export const ControlsButton = ({
const timeoutRef = useRef()
const isSaving = statuses.isSaving || isPendingToStop
- const isDisabled = !isRoomConnected
+ const isDisabled = !isRoomConnected || statuses.isAnotherModeStarted
useEffect(() => {
if (isSaving) {
@@ -103,8 +107,57 @@ export const ControlsButton = ({
// Inactive state (Start button)
return (
+ {statuses.isAnotherModeStarted && (
+ openSidePanel()}
+ >
+
+ info
+
+
+ {parseLineBreaks(t('button.anotherModeStarted'))}
+
+
+ chevron_right
+
+
+ )}
)
diff --git a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx
index 15bdbaf8..82661635 100644
--- a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx
+++ b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx
@@ -32,6 +32,7 @@ import { NoAccessView } from './NoAccessView'
import { ControlsButton } from './ControlsButton'
import { RowWrapper } from './RowWrapper'
import { useMutateRecording } from '../hooks/useMutateRecording'
+import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
export const TranscriptSidePanel = () => {
const { data } = useConfig()
@@ -66,6 +67,7 @@ export const TranscriptSidePanel = () => {
const statuses = useRecordingStatuses(RecordingMode.Transcript)
const room = useRoomContext()
+ const { openScreenRecording } = useSidePanel()
const handleTranscript = async () => {
if (!roomId) {
@@ -241,6 +243,7 @@ export const TranscriptSidePanel = () => {
statuses={statuses}
isPendingToStart={isPendingToStart}
isPendingToStop={isPendingToStop}
+ openSidePanel={openScreenRecording}
/>
)
diff --git a/src/frontend/src/features/recording/hooks/useRecordingStatuses.ts b/src/frontend/src/features/recording/hooks/useRecordingStatuses.ts
index 78ea4df6..38ab40fa 100644
--- a/src/frontend/src/features/recording/hooks/useRecordingStatuses.ts
+++ b/src/frontend/src/features/recording/hooks/useRecordingStatuses.ts
@@ -2,7 +2,20 @@ import { RecordingMode } from '@/features/recording'
import { useRoomMetadata } from './useRoomMetadata'
import { useMemo } from 'react'
+export enum RecordingStatus {
+ Starting = 'starting',
+ Started = 'started',
+ Saving = 'saving',
+}
+
+const ACTIVE_STATUSES = [
+ RecordingStatus.Starting,
+ RecordingStatus.Started,
+ RecordingStatus.Saving,
+] as const
+
export interface RecordingStatuses {
+ isAnotherModeStarted: boolean
isStarting: boolean
isStarted: boolean
isSaving: boolean
@@ -17,16 +30,23 @@ export const useRecordingStatuses = (
return useMemo(() => {
if (metadata && metadata?.recording_mode === mode) {
return {
- isStarting: metadata.recording_status === 'starting',
- isStarted: metadata.recording_status === 'started',
- isSaving: metadata.recording_status === 'saving',
- isActive: ['starting', 'started', 'saving'].includes(
- metadata.recording_status
+ isAnotherModeStarted: false,
+ isStarting: metadata.recording_status === RecordingStatus.Starting,
+ isStarted: metadata.recording_status === RecordingStatus.Started,
+ isSaving: metadata.recording_status === RecordingStatus.Saving,
+ isActive: ACTIVE_STATUSES.includes(
+ metadata.recording_status as RecordingStatus
),
}
}
+ const isAnotherModeStarted =
+ !!metadata?.recording_mode &&
+ metadata?.recording_mode !== mode &&
+ ACTIVE_STATUSES.includes(metadata.recording_status as RecordingStatus)
+
return {
+ isAnotherModeStarted,
isStarting: false,
isStarted: false,
isSaving: false,
diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json
index c9492f10..8b2a5c48 100644
--- a/src/frontend/src/locales/de/rooms.json
+++ b/src/frontend/src/locales/de/rooms.json
@@ -324,7 +324,8 @@
"start": "Meeting transkribieren starten",
"stop": "Meeting transkribieren beenden",
"saving": "Speichern…",
- "starting": "Wird gestartet…"
+ "starting": "Wird gestartet…",
+ "anotherModeStarted": "Eine Aufnahme läuft.
Wechseln Sie das Menü und stoppen Sie sie."
},
"linkMore": "Mehr erfahren",
"notAdminOrOwner": {
@@ -362,7 +363,8 @@
"start": "Meeting-Aufzeichnung starten",
"stop": "Meeting-Aufzeichnung beenden",
"saving": "Wird gespeichert…",
- "starting": "Wird gestartet…"
+ "starting": "Wird gestartet…",
+ "anotherModeStarted": "Eine Transkription läuft.
Wechseln Sie das Menü und stoppen Sie sie."
},
"notAdminOrOwner": {
"heading": "Zugriff eingeschränkt",
diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json
index d996104e..101a9717 100644
--- a/src/frontend/src/locales/en/rooms.json
+++ b/src/frontend/src/locales/en/rooms.json
@@ -324,7 +324,8 @@
"start": "Start transcribing the meeting",
"stop": "Stop transcribing the meeting",
"saving": "Saving…",
- "starting": "Starting…"
+ "starting": "Starting…",
+ "anotherModeStarted": "Screen recording is running. Switch panels and stop it."
},
"linkMore": "Learn more",
"notAdminOrOwner": {
@@ -362,7 +363,8 @@
"start": "Start recording the meeting",
"stop": "Stop recording the meeting",
"saving": "Saving…",
- "starting": "Starting…"
+ "starting": "Starting…",
+ "anotherModeStarted": "Transcription is running.
Switch panels and stop it."
},
"notAdminOrOwner": {
"heading": "Restricted Access",
diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json
index 30c5dbc5..31d2e6d3 100644
--- a/src/frontend/src/locales/fr/rooms.json
+++ b/src/frontend/src/locales/fr/rooms.json
@@ -324,7 +324,8 @@
"start": "Commencer à transcrire la réunion",
"stop": "Arrêter de transcrire la réunion",
"saving": "Sauvegarde…",
- "starting": "Démarrage…"
+ "starting": "Démarrage…",
+ "anotherModeStarted": "Un enregistrement est en cours.
Changez de menu et arrêtez le."
},
"linkMore": "En savoir plus",
"notAdminOrOwner": {
@@ -362,7 +363,8 @@
"start": "Commencer à enregistrer la réunion",
"stop": "Arrêter d'enregistrer la réunion",
"saving": "Sauvegarde…",
- "starting": "Démarrage…"
+ "starting": "Démarrage…",
+ "anotherModeStarted": "Une transcription est en cours.
Changez de menu et arrêtez la."
},
"notAdminOrOwner": {
"heading": "Accès restreint",
diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json
index dc433fc8..26851cd6 100644
--- a/src/frontend/src/locales/nl/rooms.json
+++ b/src/frontend/src/locales/nl/rooms.json
@@ -324,7 +324,8 @@
"start": "Begin met het transcriberen van de vergadering",
"stop": "Stop met het transcriberen van de vergadering",
"saving": "Opslaan…",
- "starting": "Wordt gestart…"
+ "starting": "Wordt gestart…",
+ "anotherModeStarted": "Er loopt een opname.
Ga naar het menu en stop deze."
},
"linkMore": "Meer informatie",
"notAdminOrOwner": {
@@ -362,7 +363,8 @@
"start": "Start met opnemen van de vergadering",
"stop": "Stop met opnemen van de vergadering",
"saving": "Bezig met opslaan…",
- "starting": "Wordt gestart…"
+ "starting": "Wordt gestart…",
+ "anotherModeStarted": "Er loopt een transcriptie.
Ga naar het menu en stop deze."
},
"notAdminOrOwner": {
"heading": "Toegang beperkt",
diff --git a/src/frontend/src/utils/parseLineBreaks.tsx b/src/frontend/src/utils/parseLineBreaks.tsx
new file mode 100644
index 00000000..335df8c3
--- /dev/null
+++ b/src/frontend/src/utils/parseLineBreaks.tsx
@@ -0,0 +1,12 @@
+import { Fragment, ReactNode } from 'react'
+
+export const parseLineBreaks = (text: string): ReactNode[] => {
+ const parts = text.split(/(
)/gi)
+
+ return parts.map((part, index) => {
+ if (part.match(/^
$/gi)) {
+ return
+ }
+ return {part}
+ })
+}