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} + }) +}