Compare commits

..

3 Commits

Author SHA1 Message Date
lebaudantoine 6593e449e2 🐛(frontend) prevent Crisp crash when superuser has no email
Fix crash when switching from admin session to app with superuser account
that lacks email field. Add null check to prevent Crisp initialization
errors.
2025-07-20 17:55:38 +02:00
lebaudantoine de6b8e1e22 🌐(frontend) internationalize missing error message
Add translation support for previously untranslated error message to
complete localization coverage.
2025-07-20 17:52:26 +02:00
ericboucher 7ddf9070aa 🚸(frontend) display email with username to clarify logged-in account
Show email alongside full name when available to prevent user confusion
about which account is currently logged in. Enhances general app UX.
2025-07-20 17:45:51 +02:00
31 changed files with 162 additions and 406 deletions
+1 -1
View File
@@ -212,7 +212,7 @@ class LobbyService:
try:
utils.notify_participants(
room_name=str(room_id),
room_name=room_id,
notification_data={
"type": settings.LOBBY_NOTIFICATION_TYPE,
},
@@ -442,7 +442,7 @@ def test_enter_success(
timeout=settings.LOBBY_WAITING_TIMEOUT,
)
mock_notify.assert_called_once_with(
room_name=str(room.id), notification_data={"type": "participantWaiting"}
room_name=room.id, notification_data={"type": "participantWaiting"}
)
+1 -1
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "meet"
version = "0.1.30"
version = "0.1.29"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
+2 -54
View File
@@ -1,19 +1,18 @@
{
"name": "meet",
"version": "0.1.30",
"version": "0.1.29",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "meet",
"version": "0.1.30",
"version": "0.1.29",
"dependencies": {
"@livekit/components-react": "2.9.13",
"@livekit/components-styles": "1.1.6",
"@livekit/track-processors": "0.5.7",
"@pandacss/preset-panda": "0.54.0",
"@react-aria/toast": "3.0.5",
"@react-hook/size": "2.1.2",
"@remixicon/react": "4.6.0",
"@tanstack/react-query": "5.81.5",
"@timephy/rnnoise-wasm": "1.0.0",
@@ -1211,12 +1210,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@juggle/resize-observer": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==",
"license": "Apache-2.0"
},
"node_modules/@livekit/components-core": {
"version": "0.12.8",
"resolved": "https://registry.npmjs.org/@livekit/components-core/-/components-core-0.12.8.tgz",
@@ -2708,51 +2701,6 @@
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/@react-hook/latest": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/passive-layout-effect": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz",
"integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/resize-observer": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@react-hook/resize-observer/-/resize-observer-1.2.6.tgz",
"integrity": "sha512-DlBXtLSW0DqYYTW3Ft1/GQFZlTdKY5VAFIC4+km6IK5NiPPDFchGbEJm1j6pSgMqPRHbUQgHJX7RaR76ic1LWA==",
"license": "MIT",
"dependencies": {
"@juggle/resize-observer": "^3.3.1",
"@react-hook/latest": "^1.0.2",
"@react-hook/passive-layout-effect": "^1.2.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/size": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@react-hook/size/-/size-2.1.2.tgz",
"integrity": "sha512-BmE5asyRDxSuQ9p14FUKJ0iBRgV9cROjqNG9jT/EjCM+xHha1HVqbPoT+14FQg1K7xIydabClCibUY4+1tw/iw==",
"license": "MIT",
"dependencies": {
"@react-hook/passive-layout-effect": "^1.2.0",
"@react-hook/resize-observer": "^1.2.1"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-stately/autocomplete": {
"version": "3.0.0-beta.2",
"resolved": "https://registry.npmjs.org/@react-stately/autocomplete/-/autocomplete-3.0.0-beta.2.tgz",
+1 -2
View File
@@ -1,7 +1,7 @@
{
"name": "meet",
"private": true,
"version": "0.1.30",
"version": "0.1.29",
"type": "module",
"scripts": {
"dev": "panda codegen && vite",
@@ -18,7 +18,6 @@
"@livekit/track-processors": "0.5.7",
"@pandacss/preset-panda": "0.54.0",
"@react-aria/toast": "3.0.5",
"@react-hook/size": "2.1.2",
"@remixicon/react": "4.6.0",
"@tanstack/react-query": "5.81.5",
"@timephy/rnnoise-wasm": "1.0.0",
@@ -7,8 +7,6 @@ import {
MediaDeviceFailure,
Room,
RoomOptions,
supportsAdaptiveStream,
supportsDynacast,
} from 'livekit-client'
import { keys } from '@/api/queryKeys'
import { queryClient } from '@/api/queryClient'
@@ -76,8 +74,8 @@ export const Conference = ({
const roomOptions = useMemo((): RoomOptions => {
return {
adaptiveStream: supportsAdaptiveStream(),
dynacast: supportsDynacast(),
adaptiveStream: true,
dynacast: true,
publishDefaults: {
videoCodec: 'vp9',
},
@@ -4,9 +4,9 @@ import { useMemo, useRef } from 'react'
import { ScreenSharePreferenceStore } from '@/stores/ScreenSharePreferences'
import { useSnapshot } from 'valtio'
import { useLocalParticipant } from '@livekit/components-react'
import { useSize } from '../hooks/useResizeObserver'
import { TrackReferenceOrPlaceholder } from '@livekit/components-core'
import { useTranslation } from 'react-i18next'
import useSize from '@react-hook/size'
export const FullScreenShareWarning = ({
trackReference,
@@ -16,7 +16,7 @@ export const FullScreenShareWarning = ({
const { t } = useTranslation('rooms', { keyPrefix: 'fullScreenWarning' })
const warningContainerRef = useRef<HTMLDivElement>(null)
const containerWidth = useSize(warningContainerRef)[0]
const { width: containerWidth } = useSize(warningContainerRef)
const { localParticipant } = useLocalParticipant()
const screenSharePreferences = useSnapshot(ScreenSharePreferenceStore)
@@ -3,8 +3,8 @@ import { styled } from '@/styled-system/jsx'
import { Avatar } from '@/components/Avatar'
import { useIsSpeaking } from '@livekit/components-react'
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
import { useSize } from '@/features/rooms/livekit/hooks/useResizeObserver'
import { useMemo, useRef } from 'react'
import useSize from '@react-hook/size'
const StyledParticipantPlaceHolder = styled('div', {
base: {
@@ -28,7 +28,7 @@ export const ParticipantPlaceholder = ({
const participantColor = getParticipantColor(participant)
const placeholderEl = useRef<HTMLDivElement>(null)
const [width, height] = useSize(placeholderEl)
const { width, height } = useSize(placeholderEl)
const minDimension = Math.min(width, height)
const avatarSize = useMemo(
@@ -1,55 +0,0 @@
import * as React from 'react'
import { createInteractingObservable } from '@livekit/components-core'
import { usePagination } from '@livekit/components-react'
import { RiArrowLeftSLine, RiArrowRightSLine } from '@remixicon/react'
export interface PaginationControlProps
extends Pick<
ReturnType<typeof usePagination>,
'totalPageCount' | 'nextPage' | 'prevPage' | 'currentPage'
> {
/** Reference to an HTML element that holds the pages, while interacting (`mouseover`)
* with it, the pagination controls will appear for a while. */
pagesContainer?: React.RefObject<HTMLElement>
}
export function PaginationControl({
totalPageCount,
nextPage,
prevPage,
currentPage,
pagesContainer: connectedElement,
}: PaginationControlProps) {
const [interactive, setInteractive] = React.useState(false)
React.useEffect(() => {
let subscription:
| ReturnType<ReturnType<typeof createInteractingObservable>['subscribe']>
| undefined
if (connectedElement) {
subscription = createInteractingObservable(
connectedElement.current,
2000
).subscribe(setInteractive)
}
return () => {
if (subscription) {
subscription.unsubscribe()
}
}
}, [connectedElement])
return (
<div
className="lk-pagination-control"
data-lk-user-interaction={interactive}
>
<button className="lk-button" onClick={prevPage}>
<RiArrowLeftSLine />
</button>
<span className="lk-pagination-count">{`${currentPage} of ${totalPageCount}`}</span>
<button className="lk-button" onClick={nextPage}>
<RiArrowRightSLine />
</button>
</div>
)
}
@@ -1,30 +0,0 @@
import * as React from 'react'
export interface PaginationIndicatorProps {
totalPageCount: number
currentPage: number
}
export const PaginationIndicator: (
props: PaginationIndicatorProps & React.RefAttributes<HTMLDivElement>
) => React.ReactNode = /* @__PURE__ */ React.forwardRef<
HTMLDivElement,
PaginationIndicatorProps
>(function PaginationIndicator(
{ totalPageCount, currentPage }: PaginationIndicatorProps,
ref
) {
const bubbles = new Array(totalPageCount).fill('').map((_, index) => {
if (index + 1 === currentPage) {
return <span data-lk-active key={index} />
} else {
return <span key={index} />
}
})
return (
<div ref={ref} className="lk-pagination-indicator">
{bubbles}
</div>
)
})
@@ -1,92 +0,0 @@
import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
import { getScrollBarWidth } from '@livekit/components-core'
import * as React from 'react'
import { TrackLoop, useVisualStableUpdate } from '@livekit/components-react'
import useSize from '@react-hook/size'
const MIN_HEIGHT = 130
const MIN_WIDTH = 140
const MIN_VISIBLE_TILES = 1
const ASPECT_RATIO = 16 / 10
const ASPECT_RATIO_INVERT = (1 - ASPECT_RATIO) * -1
/** @public */
export interface CarouselLayoutProps
extends React.HTMLAttributes<HTMLMediaElement> {
tracks: TrackReferenceOrPlaceholder[]
children: React.ReactNode
/** Place the tiles vertically or horizontally next to each other.
* If undefined orientation is guessed by the dimensions of the container. */
orientation?: 'vertical' | 'horizontal'
}
/**
* The `CarouselLayout` component displays a list of tracks in a scroll container.
* It will display as many tiles as possible and overflow the rest.
* @remarks
* To ensure visual stability when tiles are reordered due to track updates,
* the component uses the `useVisualStableUpdate` hook.
* @example
* ```tsx
* const tracks = useTracks([Track.Source.Camera]);
* <CarouselLayout tracks={tracks}>
* <ParticipantTile />
* </CarouselLayout>
* ```
* @public
*/
export function CarouselLayout({
tracks,
orientation,
...props
}: CarouselLayoutProps) {
const asideEl = React.useRef<HTMLDivElement>(null)
const [prevTiles, setPrevTiles] = React.useState(0)
const [width, height] = useSize(asideEl)
const carouselOrientation = orientation
? orientation
: height >= width
? 'vertical'
: 'horizontal'
const tileSpan =
carouselOrientation === 'vertical'
? Math.max(width * ASPECT_RATIO_INVERT, MIN_HEIGHT)
: Math.max(height * ASPECT_RATIO, MIN_WIDTH)
const scrollBarWidth = getScrollBarWidth()
const tilesThatFit =
carouselOrientation === 'vertical'
? Math.max((height - scrollBarWidth) / tileSpan, MIN_VISIBLE_TILES)
: Math.max((width - scrollBarWidth) / tileSpan, MIN_VISIBLE_TILES)
let maxVisibleTiles = Math.round(tilesThatFit)
if (Math.abs(tilesThatFit - prevTiles) < 0.5) {
maxVisibleTiles = Math.round(prevTiles)
} else if (prevTiles !== tilesThatFit) {
setPrevTiles(tilesThatFit)
}
const sortedTiles = useVisualStableUpdate(tracks, maxVisibleTiles)
React.useLayoutEffect(() => {
if (asideEl.current) {
asideEl.current.dataset.lkOrientation = carouselOrientation
asideEl.current.style.setProperty(
'--lk-max-visible-tiles',
maxVisibleTiles.toString()
)
}
}, [maxVisibleTiles, carouselOrientation])
return (
<aside
key={carouselOrientation}
className="lk-carousel"
ref={asideEl}
{...props}
>
<TrackLoop tracks={sortedTiles}>{props.children}</TrackLoop>
</aside>
)
}
@@ -1,71 +0,0 @@
import * as React from 'react'
import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
import {
TrackLoop,
usePagination,
UseParticipantsOptions,
useSwipe,
} from '@livekit/components-react'
import { mergeProps } from '@/utils/mergeProps'
import { PaginationIndicator } from '../controls/PaginationIndicator'
import { useGridLayout } from '../../hooks/useGridLayout'
import { PaginationControl } from '../controls/PaginationControl'
/** @public */
export interface GridLayoutProps
extends React.HTMLAttributes<HTMLDivElement>,
Pick<UseParticipantsOptions, 'updateOnlyOn'> {
children: React.ReactNode
tracks: TrackReferenceOrPlaceholder[]
}
/**
* The `GridLayout` component displays the nested participants in a grid where every participants has the same size.
* It also supports pagination if there are more participants than the grid can display.
* @remarks
* To ensure visual stability when tiles are reordered due to track updates,
* the component uses the `useVisualStableUpdate` hook.
* @example
* ```tsx
* <LiveKitRoom>
* <GridLayout tracks={tracks}>
* <ParticipantTile />
* </GridLayout>
* <LiveKitRoom>
* ```
* @public
*/
export function GridLayout({ tracks, ...props }: GridLayoutProps) {
const gridEl = React.createRef<HTMLDivElement>()
const elementProps = React.useMemo(
() => mergeProps(props, { className: 'lk-grid-layout' }),
[props]
)
const { layout } = useGridLayout(gridEl, tracks.length)
const pagination = usePagination(layout.maxTiles, tracks)
useSwipe(gridEl, {
onLeftSwipe: pagination.nextPage,
onRightSwipe: pagination.prevPage,
})
return (
<div
ref={gridEl}
data-lk-pagination={pagination.totalPageCount > 1}
{...elementProps}
>
<TrackLoop tracks={pagination.tracks}>{props.children}</TrackLoop>
{tracks.length > layout.maxTiles && (
<>
<PaginationIndicator
totalPageCount={pagination.totalPageCount}
currentPage={pagination.currentPage}
/>
<PaginationControl pagesContainer={gridEl} {...pagination} />
</>
)}
</div>
)
}
@@ -1,53 +0,0 @@
import { GRID_LAYOUTS, selectGridLayout } from '@livekit/components-core'
import type {
GridLayoutDefinition,
GridLayoutInfo,
} from '@livekit/components-core'
import * as React from 'react'
import useSize from '@react-hook/size'
/**
* The `useGridLayout` hook tries to select the best layout to fit all tiles.
* If the available screen space is not enough, it will reduce the number of maximum visible
* tiles and select a layout that still works visually within the given limitations.
* As the order of tiles changes over time, the hook tries to keep visual updates to a minimum
* while trying to display important tiles such as speaking participants or screen shares.
*
* @example
* ```tsx
* const { layout } = useGridLayout(gridElement, trackCount);
* ```
* @public
*/
export function useGridLayout(
/** HTML element that contains the grid. */
gridElement: React.RefObject<HTMLDivElement>,
/** Count of tracks that should get layed out */
trackCount: number,
options: {
gridLayouts?: GridLayoutDefinition[]
} = {}
): { layout: GridLayoutInfo; containerWidth: number; containerHeight: number } {
const gridLayouts = options.gridLayouts ?? GRID_LAYOUTS
const [width, height] = useSize(gridElement)
const layout = selectGridLayout(gridLayouts, trackCount, width, height)
React.useEffect(() => {
if (gridElement.current && layout) {
gridElement.current.style.setProperty(
'--lk-col-count',
layout?.columns.toString()
)
gridElement.current.style.setProperty(
'--lk-row-count',
layout?.rows.toString()
)
}
}, [gridElement, layout])
return {
layout,
containerWidth: width,
containerHeight: height,
}
}
@@ -0,0 +1,127 @@
/* eslint-disable react-hooks/exhaustive-deps */
import * as React from 'react'
const useLatest = <T>(current: T) => {
const storedValue = React.useRef(current)
React.useEffect(() => {
storedValue.current = current
})
return storedValue
}
/**
* A React hook that fires a callback whenever ResizeObserver detects a change to its size
* code extracted from https://github.com/jaredLunde/react-hook/blob/master/packages/resize-observer/src/index.tsx in order to not include the polyfill for resize-observer
*
* @internal
*/
export function useResizeObserver<T extends HTMLElement>(
target: React.RefObject<T>,
callback: UseResizeObserverCallback
) {
const resizeObserver = getResizeObserver()
const storedCallback = useLatest(callback)
React.useLayoutEffect(() => {
let didUnsubscribe = false
const targetEl = target.current
if (!targetEl) return
function cb(entry: ResizeObserverEntry, observer: ResizeObserver) {
if (didUnsubscribe) return
storedCallback.current(entry, observer)
}
resizeObserver?.subscribe(targetEl as HTMLElement, cb)
return () => {
didUnsubscribe = true
resizeObserver?.unsubscribe(targetEl as HTMLElement, cb)
}
}, [target.current, resizeObserver, storedCallback])
return resizeObserver?.observer
}
function createResizeObserver() {
let ticking = false
let allEntries: ResizeObserverEntry[] = []
const callbacks: Map<unknown, Array<UseResizeObserverCallback>> = new Map()
if (typeof window === 'undefined') {
return
}
const observer = new ResizeObserver(
(entries: ResizeObserverEntry[], obs: ResizeObserver) => {
allEntries = allEntries.concat(entries)
if (!ticking) {
window.requestAnimationFrame(() => {
const triggered = new Set<Element>()
for (let i = 0; i < allEntries.length; i++) {
if (triggered.has(allEntries[i].target)) continue
triggered.add(allEntries[i].target)
const cbs = callbacks.get(allEntries[i].target)
cbs?.forEach((cb) => cb(allEntries[i], obs))
}
allEntries = []
ticking = false
})
}
ticking = true
}
)
return {
observer,
subscribe(target: HTMLElement, callback: UseResizeObserverCallback) {
observer.observe(target)
const cbs = callbacks.get(target) ?? []
cbs.push(callback)
callbacks.set(target, cbs)
},
unsubscribe(target: HTMLElement, callback: UseResizeObserverCallback) {
const cbs = callbacks.get(target) ?? []
if (cbs.length === 1) {
observer.unobserve(target)
callbacks.delete(target)
return
}
const cbIndex = cbs.indexOf(callback)
if (cbIndex !== -1) cbs.splice(cbIndex, 1)
callbacks.set(target, cbs)
},
}
}
let _resizeObserver: ReturnType<typeof createResizeObserver>
const getResizeObserver = () =>
!_resizeObserver
? (_resizeObserver = createResizeObserver())
: _resizeObserver
export type UseResizeObserverCallback = (
entry: ResizeObserverEntry,
observer: ResizeObserver
) => unknown
export const useSize = (target: React.RefObject<HTMLDivElement>) => {
const [size, setSize] = React.useState({ width: 0, height: 0 })
React.useLayoutEffect(() => {
if (target.current) {
const { width, height } = target.current.getBoundingClientRect()
setSize({ width, height })
}
}, [target.current])
const resizeCallback = React.useCallback(
(entry: ResizeObserverEntry) => setSize(entry.contentRect),
[]
)
// Where the magic happens
useResizeObserver(target, resizeCallback)
return size
}
@@ -4,13 +4,13 @@ import { ParticipantsToggle } from '../../components/controls/Participants/Parti
import { ToolsToggle } from '../../components/controls/ToolsToggle'
import { InfoToggle } from '../../components/controls/InfoToggle'
import { AdminToggle } from '../../components/AdminToggle'
import { useSize } from '../../hooks/useResizeObserver'
import { useState, RefObject } from 'react'
import { Dialog, DialogTrigger, Popover } from 'react-aria-components'
import { Button } from '@/primitives'
import { ToggleButtonProps } from '@/primitives/ToggleButton'
import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import useSize from '@react-hook/size'
const CONTROL_BAR_BREAKPOINT = 1100
@@ -70,7 +70,7 @@ export const MoreOptions = ({
}: {
parentElement: RefObject<HTMLDivElement>
}) => {
const parentWidth = useSize(parentElement)[0]
const { width: parentWidth } = useSize(parentElement)
return (
<div
className={css({
@@ -9,6 +9,7 @@ import { RoomEvent, Track } from 'livekit-client'
import * as React from 'react'
import { useState } from 'react'
import {
CarouselLayout,
ConnectionStateToast,
FocusLayoutContainer,
GridLayout,
@@ -31,7 +32,6 @@ import { RecordingStateToast } from '@/features/recording'
import { ScreenShareErrorModal } from '../components/ScreenShareErrorModal'
import { useConnectionObserver } from '../hooks/useConnectionObserver'
import { useNoiseReduction } from '../hooks/useNoiseReduction'
import { CarouselLayout } from '../components/layout/CarouselLayout'
const LayoutWrapper = styled(
'div',
@@ -14,8 +14,8 @@ import { AccountTab } from './tabs/AccountTab'
import { NotificationsTab } from './tabs/NotificationsTab'
import { GeneralTab } from './tabs/GeneralTab'
import { AudioTab } from './tabs/AudioTab'
import { useSize } from '@/features/rooms/livekit/hooks/useResizeObserver'
import { useRef } from 'react'
import { useMediaQuery } from '@/features/rooms/livekit/hooks/useMediaQuery'
const tabsStyle = css({
maxHeight: '40.625rem', // fixme size copied from meet settings modal
@@ -51,7 +51,8 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => {
const { t } = useTranslation('settings')
const dialogEl = useRef<HTMLDivElement>(null)
const isWideScreen = useMediaQuery('(min-width: 800px)') // fixme - hardcoded 50rem in pixel
const { width } = useSize(dialogEl)
const isWideScreen = !width || width >= 800 // fixme - hardcoded 50rem in pixel
return (
<Dialog innerRef={dialogEl} {...props} role="dialog" type="flex">
@@ -1,4 +1,4 @@
import { DialogProps, Field, H, Switch, Text } from '@/primitives'
import { DialogProps, Field, H, Switch } from '@/primitives'
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
import {
@@ -174,7 +174,7 @@ export const AudioTab = ({ id }: AudioTabProps) => {
</RowWrapper>
{/* Safari has a known limitation where its implementation of 'enumerateDevices' does not include audio output devices.
To prevent errors or an empty selection list, we only render the speakers selection field on non-Safari browsers. */}
{!isSafari() ? (
{!isSafari() && (
<RowWrapper heading={t('audio.speakers.heading')}>
<Field
type="select"
@@ -193,13 +193,6 @@ export const AudioTab = ({ id }: AudioTabProps) => {
/>
<SoundTester />
</RowWrapper>
) : (
<RowWrapper heading={t('audio.speakers.heading')}>
<Text variant="warning" margin="md">
{t('audio.speakers.safariWarning')}
</Text>
<div />
</RowWrapper>
)}
{noiseReductionAvailable && (
<RowWrapper heading={t('audio.noiseReduction.heading')} beta>
+1 -2
View File
@@ -25,8 +25,7 @@
"heading": "Lautsprecher",
"label": "Wählen Sie Ihre Audioausgabe",
"test": "Testen",
"ongoingTest": "Soundtest läuft…",
"safariWarning": "Die Lautsprecherauswahl ist auf Safari aufgrund von Browser-Einschränkungen noch nicht verfügbar."
"ongoingTest": "Soundtest läuft…"
},
"permissionsRequired": "Berechtigungen erforderlich"
},
+1 -2
View File
@@ -25,8 +25,7 @@
"heading": "Speakers",
"label": "Select your audio output",
"test": "Test",
"ongoingTest": "Testing sound…",
"safariWarning": "Speaker selection is not available yet on Safari due to browser limitations."
"ongoingTest": "Testing sound…"
},
"permissionsRequired": "Permissions required"
},
+1 -2
View File
@@ -25,8 +25,7 @@
"heading": "Haut-parleurs",
"label": "Sélectionner votre sortie audio",
"test": "Tester",
"ongoingTest": "Test du son…",
"safariWarning": "La sélection du haut-parleur n'est pas encore disponible sur Safari en raison de limitations du navigateur."
"ongoingTest": "Test du son…"
},
"permissionsRequired": "Autorisations nécessaires"
},
+1 -2
View File
@@ -25,8 +25,7 @@
"heading": "Luidsprekers",
"label": "Selecteer uw audio-uitvoer",
"test": "Test",
"ongoingTest": "Testgeluid ...",
"safariWarning": "Luidsprekerselectie is nog niet beschikbaar op Safari vanwege browserbeperkingen."
"ongoingTest": "Testgeluid ..."
},
"permissionsRequired": "Machtigingen vereist"
},
-3
View File
@@ -53,9 +53,6 @@ export const text = cva({
note: {
color: 'default.subtle-text',
},
warning: {
color: 'danger.subtle-text',
},
smNote: {
color: 'default.subtle-text',
textStyle: 'sm',
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "mail_mjml",
"version": "0.1.30",
"version": "0.1.29",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mail_mjml",
"version": "0.1.30",
"version": "0.1.29",
"license": "MIT",
"dependencies": {
"@html-to/text-cli": "0.5.4",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "0.1.30",
"version": "0.1.29",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "sdk",
"version": "0.1.30",
"version": "0.1.29",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sdk",
"version": "0.1.30",
"version": "0.1.29",
"license": "ISC",
"workspaces": [
"./library",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "sdk",
"version": "0.1.30",
"version": "0.1.29",
"author": "",
"license": "ISC",
"description": "",
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "summary"
version = "0.1.30"
version = "0.1.29"
dependencies = [
"fastapi[standard]>=0.105.0",
"uvicorn>=0.24.0",
+2 -3
View File
@@ -107,13 +107,12 @@ class MetadataManager:
"retries": 0,
}
_required_args_count = 7
_required_args_count = 4
if len(task_args) != _required_args_count:
logger.error("Invalid number of arguments.")
return
filename, email, _, received_at, *_ = task_args
filename, email, _, received_at = task_args
initial_metadata = {
**initial_metadata,
"filename": filename,
+1 -2
View File
@@ -1,9 +1,8 @@
"""Celery Config."""
# https://github.com/danihodovic/celery-exporter
# Enable task events for Prometheus monitoring via celery-exporter.
# worker_send_task_events: Sends task lifecycle events (e.g., started, succeeded),
# worker_send_task_events: Sends task lifecycle events (e.g., started, succeeded, failed),
# allowing the exporter to track task execution metrics and durations.
worker_send_task_events = True
+1 -1
View File
@@ -37,7 +37,7 @@ celery = Celery(
broker_connection_retry_on_startup=True,
)
celery.config_from_object("summary.core.celery_config")
celery.config_from_object('summary.core.celery_config')
if settings.sentry_dsn and settings.sentry_is_enabled: