Merge remote-tracking branch 'origin/develop' into gsouquet/fix-backdrop-filter
* origin/develop: (43 commits) Update copy to indicate debug logs contain which UI elements you last interacted with Fix name of Netlify workflow Add type declarations Fix pagination and improve typing Fix import Reset matrix-js-sdk back to develop branch v3.28.1 Prepare changelog for v3.28.1 Upgrade matrix-js-sdk to 12.3.1 Explicitly handle first state change Properly listen for call_state Proper init in constructors Resetting package fields for development v3.28.0 Prepare changelog for v3.28.0 Fix error on accessing encrypted media without keys Fix call tile buttons Upgrade matrix-js-sdk to 12.3.0 Remove test code; good job we have tests Fix dates ...
This commit is contained in:
commit
455a914cf3
23 changed files with 613 additions and 125 deletions
|
@ -55,7 +55,7 @@ import { getKeyBindingsManager, NavigationAction, RoomAction } from '../../KeyBi
|
|||
import { IOpts } from "../../createRoom";
|
||||
import SpacePanel from "../views/spaces/SpacePanel";
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
|
||||
import CallHandler from '../../CallHandler';
|
||||
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
|
||||
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
|
||||
import { OwnProfileStore } from '../../stores/OwnProfileStore';
|
||||
|
@ -147,6 +147,7 @@ interface IState {
|
|||
class LoggedInView extends React.Component<IProps, IState> {
|
||||
static displayName = 'LoggedInView';
|
||||
|
||||
private dispatcherRef: string;
|
||||
protected readonly _matrixClient: MatrixClient;
|
||||
protected readonly _roomView: React.RefObject<any>;
|
||||
protected readonly _resizeContainer: React.RefObject<ResizeHandle>;
|
||||
|
@ -161,7 +162,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
// use compact timeline view
|
||||
useCompactLayout: SettingsStore.getValue('useCompactLayout'),
|
||||
usageLimitDismissed: false,
|
||||
activeCalls: [],
|
||||
activeCalls: CallHandler.sharedInstance().getAllActiveCalls(),
|
||||
};
|
||||
|
||||
// stash the MatrixClient in case we log out before we are unmounted
|
||||
|
@ -177,7 +178,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
|
||||
componentDidMount() {
|
||||
document.addEventListener('keydown', this.onNativeKeyDown, false);
|
||||
CallHandler.sharedInstance().addListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
|
||||
this.updateServerNoticeEvents();
|
||||
|
||||
|
@ -205,7 +206,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.onNativeKeyDown, false);
|
||||
CallHandler.sharedInstance().removeListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this._matrixClient.removeListener("accountData", this.onAccountData);
|
||||
this._matrixClient.removeListener("sync", this.onSync);
|
||||
this._matrixClient.removeListener("RoomState.events", this.onRoomStateEvents);
|
||||
|
@ -224,6 +225,17 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
this.setState({
|
||||
activeCalls: CallHandler.sharedInstance().getAllActiveCalls(),
|
||||
});
|
||||
|
||||
private onAction = (payload): void => {
|
||||
switch (payload.action) {
|
||||
case 'call_state': {
|
||||
const activeCalls = CallHandler.sharedInstance().getAllActiveCalls();
|
||||
if (activeCalls !== this.state.activeCalls) {
|
||||
this.setState({ activeCalls });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public canResetTimelineInRoom = (roomId: string) => {
|
||||
|
|
|
@ -108,6 +108,7 @@ import SoftLogout from './auth/SoftLogout';
|
|||
import { makeRoomPermalink } from "../../utils/permalinks/Permalinks";
|
||||
import { copyPlaintext } from "../../utils/strings";
|
||||
import { PosthogAnalytics } from '../../PosthogAnalytics';
|
||||
import { initSentry } from "../../sentry";
|
||||
|
||||
/** constants for MatrixChat.state.view */
|
||||
export enum Views {
|
||||
|
@ -393,6 +394,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
PosthogAnalytics.instance.updatePlatformSuperProperties();
|
||||
|
||||
CountlyAnalytics.instance.enable(/* anonymous = */ true);
|
||||
|
||||
initSentry(SdkConfig.get()["sentry"]);
|
||||
}
|
||||
|
||||
private async postLoginSetup() {
|
||||
|
|
|
@ -29,11 +29,13 @@ import BaseDialog from "./BaseDialog";
|
|||
import Field from '../elements/Field';
|
||||
import Spinner from "../elements/Spinner";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import { sendSentryReport } from "../../../sentry";
|
||||
|
||||
interface IProps {
|
||||
onFinished: (success: boolean) => void;
|
||||
initialText?: string;
|
||||
label?: string;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -113,6 +115,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
sendSentryReport(this.state.text, this.state.issueUrl, this.props.error);
|
||||
};
|
||||
|
||||
private onDownload = async (): Promise<void> => {
|
||||
|
@ -200,8 +204,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
|||
{ _t(
|
||||
"Debug logs contain application usage data including your " +
|
||||
"username, the IDs or aliases of the rooms or groups you " +
|
||||
"have visited and the usernames of other users. They do " +
|
||||
"not contain messages.",
|
||||
"have visited, which UI elements you last interacted with, " +
|
||||
"and the usernames of other users. They do not contain messages.",
|
||||
) }
|
||||
</p>
|
||||
<p><b>
|
||||
|
|
|
@ -71,6 +71,7 @@ export default class ErrorBoundary extends React.PureComponent<{}, IState> {
|
|||
private onBugReport = (): void => {
|
||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
|
||||
label: 'react-soft-crash',
|
||||
error: this.state.error,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -93,8 +94,9 @@ export default class ErrorBoundary extends React.PureComponent<{}, IState> {
|
|||
"If you've submitted a bug via GitHub, debug logs can help " +
|
||||
"us track down the problem. Debug logs contain application " +
|
||||
"usage data including your username, the IDs or aliases of " +
|
||||
"the rooms or groups you have visited and the usernames of " +
|
||||
"other users. They do not contain messages.",
|
||||
"the rooms or groups you have visited, which UI elements you " +
|
||||
"last interacted with, and the usernames of other users. " +
|
||||
"They do not contain messages.",
|
||||
) }</p>
|
||||
<AccessibleButton onClick={this.onBugReport} kind='primary'>
|
||||
{ _t("Submit debug logs") }
|
||||
|
|
|
@ -27,7 +27,7 @@ import classNames from 'classnames';
|
|||
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
|
||||
import { formatCallTime } from "../../../DateUtils";
|
||||
|
||||
const MAX_NON_NARROW_WIDTH = 400 / 70 * 100;
|
||||
const MAX_NON_NARROW_WIDTH = 450 / 70 * 100;
|
||||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
|
|
|
@ -178,7 +178,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
|
||||
private onPlaceholderClick = async () => {
|
||||
const mediaHelper = this.props.mediaEventHelper;
|
||||
if (mediaHelper.media.isEncrypted) {
|
||||
if (mediaHelper?.media.isEncrypted) {
|
||||
await this.decryptFile();
|
||||
this.downloadFile(this.fileName, this.linkText);
|
||||
} else {
|
||||
|
@ -192,7 +192,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
public render() {
|
||||
const isEncrypted = this.props.mediaEventHelper.media.isEncrypted;
|
||||
const isEncrypted = this.props.mediaEventHelper?.media.isEncrypted;
|
||||
const contentUrl = this.getContentUrl();
|
||||
const fileSize = this.content.info ? this.content.info.size : null;
|
||||
const fileType = this.content.info ? this.content.info.mimetype : "application/octet-stream";
|
||||
|
|
|
@ -51,6 +51,7 @@ export default class TileErrorBoundary extends React.Component<IProps, IState> {
|
|||
private onBugReport = (): void => {
|
||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
|
||||
label: 'react-soft-crash-tile',
|
||||
error: this.state.error,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -856,13 +856,14 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
|
||||
render() {
|
||||
const msgtype = this.props.mxEvent.getContent().msgtype;
|
||||
const eventType = this.props.mxEvent.getType() as EventType;
|
||||
const { tileHandler, isBubbleMessage, isInfoMessage } = getEventDisplayInfo(this.props.mxEvent);
|
||||
|
||||
// This shouldn't happen: the caller should check we support this type
|
||||
// before trying to instantiate us
|
||||
if (!tileHandler) {
|
||||
const { mxEvent } = this.props;
|
||||
console.warn(`Event type not supported: type:${mxEvent.getType()} isState:${mxEvent.isState()}`);
|
||||
console.warn(`Event type not supported: type:${eventType} isState:${mxEvent.isState()}`);
|
||||
return <div className="mx_EventTile mx_EventTile_info mx_MNoticeBody">
|
||||
<div className="mx_EventTile_line">
|
||||
{ _t('This event could not be displayed') }
|
||||
|
@ -886,7 +887,10 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
mx_EventTile_sending: !isEditing && isSending,
|
||||
mx_EventTile_highlight: this.props.tileShape === TileShape.Notif ? false : this.shouldHighlight(),
|
||||
mx_EventTile_selected: this.props.isSelectedEvent,
|
||||
mx_EventTile_continuation: this.props.tileShape ? '' : this.props.continuation,
|
||||
mx_EventTile_continuation: (
|
||||
(this.props.tileShape ? '' : this.props.continuation) ||
|
||||
eventType === EventType.CallInvite
|
||||
),
|
||||
mx_EventTile_last: this.props.last,
|
||||
mx_EventTile_lastInSection: this.props.lastInSection,
|
||||
mx_EventTile_contextual: this.props.contextual,
|
||||
|
@ -934,7 +938,7 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
needsSenderProfile = true;
|
||||
} else if (
|
||||
(this.props.continuation && this.props.tileShape !== TileShape.FileGrid) ||
|
||||
this.props.mxEvent.getType() === EventType.CallInvite
|
||||
eventType === EventType.CallInvite
|
||||
) {
|
||||
// no avatar or sender profile for continuation messages and call tiles
|
||||
avatarSize = 0;
|
||||
|
|
|
@ -268,7 +268,8 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
|||
"If you've submitted a bug via GitHub, debug logs can help " +
|
||||
"us track down the problem. Debug logs contain application " +
|
||||
"usage data including your username, the IDs or aliases of " +
|
||||
"the rooms or groups you have visited and the usernames of " +
|
||||
"the rooms or groups you have visited, which UI elements you " +
|
||||
"last interacted with, and the usernames of " +
|
||||
"other users. They do not contain messages.",
|
||||
) }
|
||||
<div className='mx_HelpUserSettingsTab_debugButton'>
|
||||
|
|
|
@ -72,7 +72,7 @@ export default class AudioFeed extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private playMedia() {
|
||||
private async playMedia() {
|
||||
const element = this.element.current;
|
||||
if (!element) return;
|
||||
this.onAudioOutputChanged(MediaDeviceHandler.getAudioOutput());
|
||||
|
@ -90,7 +90,7 @@ export default class AudioFeed extends React.Component<IProps, IState> {
|
|||
// should serialise the ones that need to be serialised but then be able to interrupt
|
||||
// them with another load() which will cancel the pending one, but since we don't call
|
||||
// load() explicitly, it shouldn't be a problem. - Dave
|
||||
element.play();
|
||||
await element.load();
|
||||
} catch (e) {
|
||||
logger.info("Failed to play media element with feed", this.props.feed, e);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ export default class AudioFeedArrayForCall extends React.Component<IProps, IStat
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
feeds: [],
|
||||
feeds: this.props.call.getRemoteFeeds(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
const { primary, secondary } = this.getOrderedFeeds(this.props.call.getFeeds());
|
||||
const { primary, secondary } = CallView.getOrderedFeeds(this.props.call.getFeeds());
|
||||
|
||||
this.state = {
|
||||
isLocalOnHold: this.props.call.isLocalOnHold(),
|
||||
|
@ -147,7 +147,16 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
static getDerivedStateFromProps(props: IProps): Partial<IState> {
|
||||
const { primary, secondary } = CallView.getOrderedFeeds(props.call.getFeeds());
|
||||
|
||||
return {
|
||||
primaryFeed: primary,
|
||||
secondaryFeeds: secondary,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IProps): void {
|
||||
if (this.props.call === prevProps.call) return;
|
||||
|
||||
this.setState({
|
||||
|
@ -201,7 +210,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onFeedsChanged = (newFeeds: Array<CallFeed>) => {
|
||||
const { primary, secondary } = this.getOrderedFeeds(newFeeds);
|
||||
const { primary, secondary } = CallView.getOrderedFeeds(newFeeds);
|
||||
this.setState({
|
||||
primaryFeed: primary,
|
||||
secondaryFeeds: secondary,
|
||||
|
@ -226,7 +235,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
this.buttonsRef.current?.showControls();
|
||||
};
|
||||
|
||||
private getOrderedFeeds(feeds: Array<CallFeed>): { primary: CallFeed, secondary: Array<CallFeed> } {
|
||||
static getOrderedFeeds(feeds: Array<CallFeed>): { primary: CallFeed, secondary: Array<CallFeed> } {
|
||||
let primary;
|
||||
|
||||
// Try to use a screensharing as primary, a remote one if possible
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private playMedia() {
|
||||
private async playMedia() {
|
||||
const element = this.element;
|
||||
if (!element) return;
|
||||
// We play audio in AudioFeed, not here
|
||||
|
@ -129,7 +129,7 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
// should serialise the ones that need to be serialised but then be able to interrupt
|
||||
// them with another load() which will cancel the pending one, but since we don't call
|
||||
// load() explicitly, it shouldn't be a problem. - Dave
|
||||
element.play();
|
||||
await element.play();
|
||||
} catch (e) {
|
||||
logger.info("Failed to play media element with feed", this.props.feed, e);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue