From 69e03860a0cd45ca767ceea2337b27eb1dee4d39 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 29 Nov 2022 16:21:51 -0500 Subject: [PATCH 1/4] Show day counts in call durations (#9641) * Show day counts in call durations Previously call durations over a day long would be truncated, for example displaying as '2h 0m 0s' instead of '1d 2h 0m 0s'. * Fix strict mode errors * Fix strings Co-authored-by: Travis Ralston --- src/DateUtils.ts | 43 ++++++++++++------- .../structures/LegacyCallEventGrouper.ts | 6 +-- .../views/messages/LegacyCallEvent.tsx | 6 +-- src/components/views/voip/CallDuration.tsx | 4 +- src/i18n/strings/en_EN.json | 3 ++ test/utils/DateUtils-test.ts | 18 +++++++- 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/DateUtils.ts b/src/DateUtils.ts index 25495b0542..e03dace213 100644 --- a/src/DateUtils.ts +++ b/src/DateUtils.ts @@ -124,19 +124,6 @@ export function formatTime(date: Date, showTwelveHour = false): string { return pad(date.getHours()) + ':' + pad(date.getMinutes()); } -export function formatCallTime(delta: Date): string { - const hours = delta.getUTCHours(); - const minutes = delta.getUTCMinutes(); - const seconds = delta.getUTCSeconds(); - - let output = ""; - if (hours) output += `${hours}h `; - if (minutes || output) output += `${minutes}m `; - if (seconds || output) output += `${seconds}s`; - - return output; -} - export function formatSeconds(inSeconds: number): string { const hours = Math.floor(inSeconds / (60 * 60)).toFixed(0).padStart(2, '0'); const minutes = Math.floor((inSeconds % (60 * 60)) / 60).toFixed(0).padStart(2, '0'); @@ -238,15 +225,16 @@ export function formatRelativeTime(date: Date, showTwelveHour = false): string { } } +const MINUTE_MS = 60000; +const HOUR_MS = MINUTE_MS * 60; +const DAY_MS = HOUR_MS * 24; + /** * Formats duration in ms to human readable string * Returns value in biggest possible unit (day, hour, min, second) * Rounds values up until unit threshold * ie. 23:13:57 -> 23h, 24:13:57 -> 1d, 44:56:56 -> 2d */ -const MINUTE_MS = 60000; -const HOUR_MS = MINUTE_MS * 60; -const DAY_MS = HOUR_MS * 24; export function formatDuration(durationMs: number): string { if (durationMs >= DAY_MS) { return _t('%(value)sd', { value: Math.round(durationMs / DAY_MS) }); @@ -259,3 +247,26 @@ export function formatDuration(durationMs: number): string { } return _t('%(value)ss', { value: Math.round(durationMs / 1000) }); } + +/** + * Formats duration in ms to human readable string + * Returns precise value down to the nearest second + * ie. 23:13:57 -> 23h 13m 57s, 44:56:56 -> 1d 20h 56m 56s + */ +export function formatPreciseDuration(durationMs: number): string { + const days = Math.floor(durationMs / DAY_MS); + const hours = Math.floor((durationMs % DAY_MS) / HOUR_MS); + const minutes = Math.floor((durationMs % HOUR_MS) / MINUTE_MS); + const seconds = Math.floor((durationMs % MINUTE_MS) / 1000); + + if (days > 0) { + return _t('%(days)sd %(hours)sh %(minutes)sm %(seconds)ss', { days, hours, minutes, seconds }); + } + if (hours > 0) { + return _t('%(hours)sh %(minutes)sm %(seconds)ss', { hours, minutes, seconds }); + } + if (minutes > 0) { + return _t('%(minutes)sm %(seconds)ss', { minutes, seconds }); + } + return _t('%(value)ss', { value: seconds }); +} diff --git a/src/components/structures/LegacyCallEventGrouper.ts b/src/components/structures/LegacyCallEventGrouper.ts index 117abdd69e..f6defe766f 100644 --- a/src/components/structures/LegacyCallEventGrouper.ts +++ b/src/components/structures/LegacyCallEventGrouper.ts @@ -119,9 +119,9 @@ export default class LegacyCallEventGrouper extends EventEmitter { return Boolean(this.reject); } - public get duration(): Date { - if (!this.hangup || !this.selectAnswer) return; - return new Date(this.hangup.getDate().getTime() - this.selectAnswer.getDate().getTime()); + public get duration(): number | null { + if (!this.hangup || !this.selectAnswer) return null; + return this.hangup.getDate().getTime() - this.selectAnswer.getDate().getTime(); } /** diff --git a/src/components/views/messages/LegacyCallEvent.tsx b/src/components/views/messages/LegacyCallEvent.tsx index 4ab3ba00c3..5704895d18 100644 --- a/src/components/views/messages/LegacyCallEvent.tsx +++ b/src/components/views/messages/LegacyCallEvent.tsx @@ -28,7 +28,7 @@ import LegacyCallEventGrouper, { import AccessibleButton from '../elements/AccessibleButton'; import InfoTooltip, { InfoTooltipKind } from '../elements/InfoTooltip'; import AccessibleTooltipButton from '../elements/AccessibleTooltipButton'; -import { formatCallTime } from "../../../DateUtils"; +import { formatPreciseDuration } from "../../../DateUtils"; import Clock from "../audio_messages/Clock"; const MAX_NON_NARROW_WIDTH = 450 / 70 * 100; @@ -172,10 +172,10 @@ export default class LegacyCallEvent extends React.PureComponent // https://github.com/vector-im/riot-android/issues/2623 // Also the correct hangup code as of VoIP v1 (with underscore) // Also, if we don't have a reason - const duration = this.props.callEventGrouper.duration; + const duration = this.props.callEventGrouper.duration!; let text = _t("Call ended"); if (duration) { - text += " • " + formatCallTime(duration); + text += " • " + formatPreciseDuration(duration); } return (
diff --git a/src/components/views/voip/CallDuration.tsx b/src/components/views/voip/CallDuration.tsx index 2965f6265b..df59ba05d9 100644 --- a/src/components/views/voip/CallDuration.tsx +++ b/src/components/views/voip/CallDuration.tsx @@ -17,7 +17,7 @@ limitations under the License. import React, { FC, useState, useEffect, memo } from "react"; import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; -import { formatCallTime } from "../../../DateUtils"; +import { formatPreciseDuration } from "../../../DateUtils"; interface CallDurationProps { delta: number; @@ -29,7 +29,7 @@ interface CallDurationProps { export const CallDuration: FC = memo(({ delta }) => { // Clock desync could lead to a negative duration, so just hide it if that happens if (delta <= 0) return null; - return
{ formatCallTime(new Date(delta)) }
; + return
{ formatPreciseDuration(delta) }
; }); interface GroupCallDurationProps { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 376133905d..c2f34afca9 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -56,6 +56,9 @@ "%(value)sh": "%(value)sh", "%(value)sm": "%(value)sm", "%(value)ss": "%(value)ss", + "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss": "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss", + "%(hours)sh %(minutes)sm %(seconds)ss": "%(hours)sh %(minutes)sm %(seconds)ss", + "%(minutes)sm %(seconds)ss": "%(minutes)sm %(seconds)ss", "Identity server has no terms of service": "Identity server has no terms of service", "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.", "Only continue if you trust the owner of the server.": "Only continue if you trust the owner of the server.", diff --git a/test/utils/DateUtils-test.ts b/test/utils/DateUtils-test.ts index 2815b972d2..55893e48d8 100644 --- a/test/utils/DateUtils-test.ts +++ b/test/utils/DateUtils-test.ts @@ -20,6 +20,7 @@ import { formatDuration, formatFullDateNoDayISO, formatTimeLeft, + formatPreciseDuration, } from "../../src/DateUtils"; import { REPEATABLE_DATE } from "../test-utils"; @@ -100,6 +101,22 @@ describe('formatDuration()', () => { }); }); +describe("formatPreciseDuration", () => { + const MINUTE_MS = 1000 * 60; + const HOUR_MS = MINUTE_MS * 60; + const DAY_MS = HOUR_MS * 24; + + it.each<[string, string, number]>([ + ['3 days, 6 hours, 48 minutes, 59 seconds', '3d 6h 48m 59s', 3 * DAY_MS + 6 * HOUR_MS + 48 * MINUTE_MS + 59000], + ['6 hours, 48 minutes, 59 seconds', '6h 48m 59s', 6 * HOUR_MS + 48 * MINUTE_MS + 59000], + ['48 minutes, 59 seconds', '48m 59s', 48 * MINUTE_MS + 59000], + ['59 seconds', '59s', 59000], + ['0 seconds', '0s', 0], + ])('%s formats to %s', (_description, expectedResult, input) => { + expect(formatPreciseDuration(input)).toEqual(expectedResult); + }); +}); + describe("formatFullDateNoDayISO", () => { it("should return ISO format", () => { expect(formatFullDateNoDayISO(REPEATABLE_DATE)).toEqual("2022-11-17T16:58:32.517Z"); @@ -108,7 +125,6 @@ describe("formatFullDateNoDayISO", () => { describe("formatTimeLeft", () => { it.each([ - [null, "0s left"], [0, "0s left"], [23, "23s left"], [60 + 23, "1m 23s left"], From 5f6b1dda8df7fb2a6939c32da75b020efc24ea7c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 29 Nov 2022 23:18:47 +0000 Subject: [PATCH 2/4] Update CODEOWNERS (#9654) --- .github/CODEOWNERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2c068fff33..16574bad79 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,4 @@ -* @matrix-org/element-web +* @matrix-org/element-web +/.github/workflows/** @matrix-org/element-web-app-team +/package.json @matrix-org/element-web-app-team +/yarn.lock @matrix-org/element-web-app-team From 70a7961681eb35ee47c40db04d314564921cc7bb Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 30 Nov 2022 08:47:29 +0100 Subject: [PATCH 3/4] Update voice broadcast time display (#9646) --- .../molecules/_VoiceBroadcastBody.pcss | 7 +- src/DateUtils.ts | 7 + .../molecules/VoiceBroadcastPlaybackBody.tsx | 12 +- .../hooks/useVoiceBroadcastPlayback.ts | 20 ++- .../models/VoiceBroadcastPlayback.ts | 31 +++- test/utils/DateUtils-test.ts | 2 + .../VoiceBroadcastPlaybackBody-test.tsx | 22 ++- .../VoiceBroadcastPlaybackBody-test.tsx.snap | 135 +++++++++++------- 8 files changed, 149 insertions(+), 87 deletions(-) diff --git a/res/css/voice-broadcast/molecules/_VoiceBroadcastBody.pcss b/res/css/voice-broadcast/molecules/_VoiceBroadcastBody.pcss index bf4118b806..3d463cbc9b 100644 --- a/res/css/voice-broadcast/molecules/_VoiceBroadcastBody.pcss +++ b/res/css/voice-broadcast/molecules/_VoiceBroadcastBody.pcss @@ -21,6 +21,10 @@ limitations under the License. display: inline-block; font-size: $font-12px; padding: $spacing-12; + + .mx_Clock { + line-height: 1; + } } .mx_VoiceBroadcastBody--pip { @@ -44,9 +48,8 @@ limitations under the License. } .mx_VoiceBroadcastBody_timerow { - align-items: center; display: flex; - gap: $spacing-4; + justify-content: space-between; } .mx_AccessibleButton.mx_VoiceBroadcastBody_blockButton { diff --git a/src/DateUtils.ts b/src/DateUtils.ts index e03dace213..b6fd8a0bee 100644 --- a/src/DateUtils.ts +++ b/src/DateUtils.ts @@ -125,6 +125,9 @@ export function formatTime(date: Date, showTwelveHour = false): string { } export function formatSeconds(inSeconds: number): string { + const isNegative = inSeconds < 0; + inSeconds = Math.abs(inSeconds); + const hours = Math.floor(inSeconds / (60 * 60)).toFixed(0).padStart(2, '0'); const minutes = Math.floor((inSeconds % (60 * 60)) / 60).toFixed(0).padStart(2, '0'); const seconds = Math.floor(((inSeconds % (60 * 60)) % 60)).toFixed(0).padStart(2, '0'); @@ -133,6 +136,10 @@ export function formatSeconds(inSeconds: number): string { if (hours !== "00") output += `${hours}:`; output += `${minutes}:${seconds}`; + if (isNegative) { + output = "-" + output; + } + return output; } diff --git a/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx b/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx index 6c16223388..7ba06a1501 100644 --- a/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx +++ b/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx @@ -46,10 +46,9 @@ export const VoiceBroadcastPlaybackBody: React.FC { const { - duration, + times, liveness, playbackState, - position, room, sender, toggle, @@ -94,7 +93,7 @@ export const VoiceBroadcastPlaybackBody: React.FC { - playback.skipTo(Math.max(0, position - SEEK_TIME)); + playback.skipTo(Math.max(0, times.position - SEEK_TIME)); }; seekBackwardButton = ; const onSeekForwardButtonClick = () => { - playback.skipTo(Math.min(duration, position + SEEK_TIME)); + playback.skipTo(Math.min(times.duration, times.position + SEEK_TIME)); }; seekForwardButton = +
- - + +
); diff --git a/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts b/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts index 1828b31d01..0b515c4437 100644 --- a/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts +++ b/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts @@ -40,18 +40,15 @@ export const useVoiceBroadcastPlayback = (playback: VoiceBroadcastPlayback) => { }, ); - const [duration, setDuration] = useState(playback.durationSeconds); + const [times, setTimes] = useState({ + duration: playback.durationSeconds, + position: playback.timeSeconds, + timeLeft: playback.timeLeftSeconds, + }); useTypedEventEmitter( playback, - VoiceBroadcastPlaybackEvent.LengthChanged, - d => setDuration(d / 1000), - ); - - const [position, setPosition] = useState(playback.timeSeconds); - useTypedEventEmitter( - playback, - VoiceBroadcastPlaybackEvent.PositionChanged, - p => setPosition(p / 1000), + VoiceBroadcastPlaybackEvent.TimesChanged, + t => setTimes(t), ); const [liveness, setLiveness] = useState(playback.getLiveness()); @@ -62,10 +59,9 @@ export const useVoiceBroadcastPlayback = (playback: VoiceBroadcastPlayback) => { ); return { - duration, + times, liveness: liveness, playbackState, - position, room: room, sender: playback.infoEvent.sender, toggle: playbackToggle, diff --git a/src/voice-broadcast/models/VoiceBroadcastPlayback.ts b/src/voice-broadcast/models/VoiceBroadcastPlayback.ts index 2c4054a825..70c7a4d82f 100644 --- a/src/voice-broadcast/models/VoiceBroadcastPlayback.ts +++ b/src/voice-broadcast/models/VoiceBroadcastPlayback.ts @@ -43,16 +43,20 @@ export enum VoiceBroadcastPlaybackState { } export enum VoiceBroadcastPlaybackEvent { - PositionChanged = "position_changed", - LengthChanged = "length_changed", + TimesChanged = "times_changed", LivenessChanged = "liveness_changed", StateChanged = "state_changed", InfoStateChanged = "info_state_changed", } +type VoiceBroadcastPlaybackTimes = { + duration: number; + position: number; + timeLeft: number; +}; + interface EventMap { - [VoiceBroadcastPlaybackEvent.PositionChanged]: (position: number) => void; - [VoiceBroadcastPlaybackEvent.LengthChanged]: (length: number) => void; + [VoiceBroadcastPlaybackEvent.TimesChanged]: (times: VoiceBroadcastPlaybackTimes) => void; [VoiceBroadcastPlaybackEvent.LivenessChanged]: (liveness: VoiceBroadcastLiveness) => void; [VoiceBroadcastPlaybackEvent.StateChanged]: ( state: VoiceBroadcastPlaybackState, @@ -229,7 +233,7 @@ export class VoiceBroadcastPlayback if (this.duration === duration) return; this.duration = duration; - this.emit(VoiceBroadcastPlaybackEvent.LengthChanged, this.duration); + this.emitTimesChanged(); this.liveData.update([this.timeSeconds, this.durationSeconds]); } @@ -237,10 +241,21 @@ export class VoiceBroadcastPlayback if (this.position === position) return; this.position = position; - this.emit(VoiceBroadcastPlaybackEvent.PositionChanged, this.position); + this.emitTimesChanged(); this.liveData.update([this.timeSeconds, this.durationSeconds]); } + private emitTimesChanged(): void { + this.emit( + VoiceBroadcastPlaybackEvent.TimesChanged, + { + duration: this.durationSeconds, + position: this.timeSeconds, + timeLeft: this.timeLeftSeconds, + }, + ); + } + private onPlaybackStateChange = async (event: MatrixEvent, newState: PlaybackState): Promise => { if (event !== this.currentlyPlaying) return; if (newState !== PlaybackState.Stopped) return; @@ -337,6 +352,10 @@ export class VoiceBroadcastPlayback return this.duration / 1000; } + public get timeLeftSeconds(): number { + return Math.round(this.durationSeconds) - this.timeSeconds; + } + public async skipTo(timeSeconds: number): Promise { const time = timeSeconds * 1000; const event = this.chunkEvents.findByTime(time); diff --git a/test/utils/DateUtils-test.ts b/test/utils/DateUtils-test.ts index 55893e48d8..9cb020571e 100644 --- a/test/utils/DateUtils-test.ts +++ b/test/utils/DateUtils-test.ts @@ -29,12 +29,14 @@ describe("formatSeconds", () => { expect(formatSeconds((60 * 60 * 3) + (60 * 31) + (55))).toBe("03:31:55"); expect(formatSeconds((60 * 60 * 3) + (60 * 0) + (55))).toBe("03:00:55"); expect(formatSeconds((60 * 60 * 3) + (60 * 31) + (0))).toBe("03:31:00"); + expect(formatSeconds(-((60 * 60 * 3) + (60 * 31) + (0)))).toBe("-03:31:00"); }); it("correctly formats time without hours", () => { expect(formatSeconds((60 * 60 * 0) + (60 * 31) + (55))).toBe("31:55"); expect(formatSeconds((60 * 60 * 0) + (60 * 0) + (55))).toBe("00:55"); expect(formatSeconds((60 * 60 * 0) + (60 * 31) + (0))).toBe("31:00"); + expect(formatSeconds(-((60 * 60 * 0) + (60 * 31) + (0)))).toBe("-31:00"); }); }); diff --git a/test/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody-test.tsx b/test/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody-test.tsx index a2e95a856e..901a4feb82 100644 --- a/test/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody-test.tsx +++ b/test/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody-test.tsx @@ -42,6 +42,7 @@ jest.mock("../../../../src/components/views/avatars/RoomAvatar", () => ({ describe("VoiceBroadcastPlaybackBody", () => { const userId = "@user:example.com"; const roomId = "!room:example.com"; + const duration = 23 * 60 + 42; // 23:42 let client: MatrixClient; let infoEvent: MatrixEvent; let playback: VoiceBroadcastPlayback; @@ -66,7 +67,7 @@ describe("VoiceBroadcastPlaybackBody", () => { jest.spyOn(playback, "getLiveness"); jest.spyOn(playback, "getState"); jest.spyOn(playback, "skipTo"); - jest.spyOn(playback, "durationSeconds", "get").mockReturnValue(23 * 60 + 42); // 23:42 + jest.spyOn(playback, "durationSeconds", "get").mockReturnValue(duration); }); describe("when rendering a buffering voice broadcast", () => { @@ -95,7 +96,11 @@ describe("VoiceBroadcastPlaybackBody", () => { describe("and being in the middle of the playback", () => { beforeEach(() => { act(() => { - playback.emit(VoiceBroadcastPlaybackEvent.PositionChanged, 10 * 60 * 1000); // 10:00 + playback.emit(VoiceBroadcastPlaybackEvent.TimesChanged, { + duration, + position: 10 * 60, + timeLeft: duration - 10 * 60, + }); }); }); @@ -146,15 +151,20 @@ describe("VoiceBroadcastPlaybackBody", () => { }); }); - describe("and the length updated", () => { + describe("and the times update", () => { beforeEach(() => { act(() => { - playback.emit(VoiceBroadcastPlaybackEvent.LengthChanged, 42000); // 00:42 + playback.emit(VoiceBroadcastPlaybackEvent.TimesChanged, { + duration, + position: 5 * 60 + 13, + timeLeft: 7 * 60 + 5, + }); }); }); - it("should render the new length", async () => { - expect(await screen.findByText("00:42")).toBeInTheDocument(); + it("should render the times", async () => { + expect(await screen.findByText("05:13")).toBeInTheDocument(); + expect(await screen.findByText("-07:05")).toBeInTheDocument(); }); }); }); diff --git a/test/voice-broadcast/components/molecules/__snapshots__/VoiceBroadcastPlaybackBody-test.tsx.snap b/test/voice-broadcast/components/molecules/__snapshots__/VoiceBroadcastPlaybackBody-test.tsx.snap index c14cf94539..f5d3e90b3c 100644 --- a/test/voice-broadcast/components/molecules/__snapshots__/VoiceBroadcastPlaybackBody-test.tsx.snap +++ b/test/voice-broadcast/components/molecules/__snapshots__/VoiceBroadcastPlaybackBody-test.tsx.snap @@ -76,23 +76,28 @@ exports[`VoiceBroadcastPlaybackBody when rendering a 0/not-live broadcast should /> +
- - 23:42 + 00:00 + + + -23:42
@@ -183,23 +188,28 @@ exports[`VoiceBroadcastPlaybackBody when rendering a 1/live broadcast should ren /> +
- - 23:42 + 00:00 + + + -23:42
@@ -291,23 +301,28 @@ exports[`VoiceBroadcastPlaybackBody when rendering a buffering voice broadcast s /> +
- - 23:42 + 00:00 + + + -23:42
@@ -390,23 +405,28 @@ exports[`VoiceBroadcastPlaybackBody when rendering a playing broadcast should re /> +
- - 23:42 + 00:00 + + + -23:42
@@ -469,23 +489,28 @@ exports[`VoiceBroadcastPlaybackBody when rendering a stopped broadcast should re /> +
- - 23:42 + 00:00 + + + -23:42
From dd91250111dcf4f398e125e14c686803315ebf5d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 30 Nov 2022 09:28:38 +0000 Subject: [PATCH 4/4] Pin @types/react* packages (#9651) * Update package.json * Update yarn.lock --- package.json | 4 ++-- yarn.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c3ab6219a7..f9733e7890 100644 --- a/package.json +++ b/package.json @@ -164,9 +164,9 @@ "@types/pako": "^1.0.1", "@types/parse5": "^6.0.0", "@types/qrcode": "^1.3.5", - "@types/react": "^17.0.49", + "@types/react": "17.0.49", "@types/react-beautiful-dnd": "^13.0.0", - "@types/react-dom": "^17.0.17", + "@types/react-dom": "17.0.17", "@types/react-test-renderer": "^17.0.1", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "^2.3.1", diff --git a/yarn.lock b/yarn.lock index 4cbb91c6ad..67badcfde4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2500,7 +2500,7 @@ dependencies: "@types/react" "*" -"@types/react-dom@<18.0.0", "@types/react-dom@^17.0.17": +"@types/react-dom@17.0.17", "@types/react-dom@<18.0.0": version "17.0.17" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== @@ -2531,7 +2531,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17", "@types/react@^17.0.49": +"@types/react@*", "@types/react@17.0.49", "@types/react@^17": version "17.0.49" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.49.tgz#df87ba4ca8b7942209c3dc655846724539dc1049" integrity sha512-CCBPMZaPhcKkYUTqFs/hOWqKjPxhTEmnZWjlHHgIMop67DsXywf9B5Os9Hz8KSacjNOgIdnZVJamwl232uxoPg==