Make SonarCloud happier (#9545)

* Make SonarCloud happier

* i18n

* Iterate

* Update AddExistingToSpaceDialog.tsx

* Update SlashCommands.tsx
This commit is contained in:
Michael Telatynski 2022-11-07 13:45:34 +00:00 committed by GitHub
parent 77764d80bc
commit 3747464b41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 131 additions and 162 deletions

View file

@ -460,7 +460,7 @@ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | s
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string; export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string;
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode; export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode;
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}) { export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}) {
const isFormattedBody = content.format === "org.matrix.custom.html" && content.formatted_body; const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body;
let bodyHasEmoji = false; let bodyHasEmoji = false;
let isHtmlMessage = false; let isHtmlMessage = false;
@ -511,7 +511,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
decodeEntities: false, decodeEntities: false,
}); });
const isPlainText = phtml.html() === phtml.root().text(); const isPlainText = phtml.html() === phtml.root().text();
isHtmlMessage = isFormattedBody && !isPlainText; isHtmlMessage = !isPlainText;
if (isHtmlMessage && SettingsStore.getValue("feature_latex_maths")) { if (isHtmlMessage && SettingsStore.getValue("feature_latex_maths")) {
// @ts-ignore - The types for `replaceWith` wrongly expect // @ts-ignore - The types for `replaceWith` wrongly expect

View file

@ -75,11 +75,13 @@ export default class Login {
* @returns {MatrixClient} * @returns {MatrixClient}
*/ */
public createTemporaryClient(): MatrixClient { public createTemporaryClient(): MatrixClient {
if (this.tempClient) return this.tempClient; // use memoization if (!this.tempClient) {
return this.tempClient = createClient({ this.tempClient = createClient({
baseUrl: this.hsUrl, baseUrl: this.hsUrl,
idBaseUrl: this.isUrl, idBaseUrl: this.isUrl,
}); });
}
return this.tempClient;
} }
public async getFlows(): Promise<Array<LoginFlow>> { public async getFlows(): Promise<Array<LoginFlow>> {

View file

@ -79,7 +79,6 @@ export default class NodeAnimator extends React.Component<IProps> {
if (oldNode && (oldNode as HTMLElement).style.left !== c.props.style.left) { if (oldNode && (oldNode as HTMLElement).style.left !== c.props.style.left) {
this.applyStyles(oldNode as HTMLElement, { left: c.props.style.left }); this.applyStyles(oldNode as HTMLElement, { left: c.props.style.left });
// console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left);
} }
// clone the old element with the props (and children) of the new element // clone the old element with the props (and children) of the new element
// so prop updates are still received by the children. // so prop updates are still received by the children.
@ -94,7 +93,6 @@ export default class NodeAnimator extends React.Component<IProps> {
if (startStyles.length > 0) { if (startStyles.length > 0) {
const startStyle = startStyles[0]; const startStyle = startStyles[0];
newProps.style = startStyle; newProps.style = startStyle;
// console.log("mounted@startstyle0: "+JSON.stringify(startStyle));
} }
newProps.ref = ((n) => this.collectNode( newProps.ref = ((n) => this.collectNode(
@ -118,18 +116,12 @@ export default class NodeAnimator extends React.Component<IProps> {
// to start with, so now we animate 1 etc. // to start with, so now we animate 1 etc.
for (let i = 1; i < startStyles.length; ++i) { for (let i = 1; i < startStyles.length; ++i) {
this.applyStyles(domNode as HTMLElement, startStyles[i]); this.applyStyles(domNode as HTMLElement, startStyles[i]);
// console.log("start:"
// JSON.stringify(startStyles[i]),
// );
} }
// and then we animate to the resting state // and then we animate to the resting state
setTimeout(() => { setTimeout(() => {
this.applyStyles(domNode as HTMLElement, restingStyle); this.applyStyles(domNode as HTMLElement, restingStyle);
}, 0); }, 0);
// console.log("enter:",
// JSON.stringify(restingStyle));
} }
this.nodes[k] = node; this.nodes[k] = node;
} }

View file

@ -47,11 +47,10 @@ import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import LegacyCallHandler from "./LegacyCallHandler"; import LegacyCallHandler from "./LegacyCallHandler";
import VoipUserMapper from "./VoipUserMapper"; import VoipUserMapper from "./VoipUserMapper";
import { SdkContextClass } from "./contexts/SDKContext"; import { SdkContextClass } from "./contexts/SDKContext";
import { localNotificationsAreSilenced } from "./utils/notifications"; import { localNotificationsAreSilenced, createLocalNotificationSettingsIfNeeded } from "./utils/notifications";
import { getIncomingCallToastKey, IncomingCallToast } from "./toasts/IncomingCallToast"; import { getIncomingCallToastKey, IncomingCallToast } from "./toasts/IncomingCallToast";
import ToastStore from "./stores/ToastStore"; import ToastStore from "./stores/ToastStore";
import { ElementCall } from "./models/Call"; import { ElementCall } from "./models/Call";
import { createLocalNotificationSettingsIfNeeded } from './utils/notifications';
/* /*
* Dispatches: * Dispatches:

View file

@ -497,11 +497,10 @@ interface IEncryptedSeshatEvent {
} }
function restoreEncryptionInfo(searchResultSlice: SearchResult[] = []): void { function restoreEncryptionInfo(searchResultSlice: SearchResult[] = []): void {
for (let i = 0; i < searchResultSlice.length; i++) { for (const result of searchResultSlice) {
const timeline = searchResultSlice[i].context.getTimeline(); const timeline = result.context.getTimeline();
for (let j = 0; j < timeline.length; j++) { for (const mxEv of timeline) {
const mxEv = timeline[j];
const ev = mxEv.event as IEncryptedSeshatEvent; const ev = mxEv.event as IEncryptedSeshatEvent;
if (ev.curve25519Key) { if (ev.curve25519Key) {

View file

@ -716,7 +716,7 @@ export const Commands = [
runFn: function(roomId, args) { runFn: function(roomId, args) {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
let targetRoomId: string; let targetRoomId: string | undefined;
if (args) { if (args) {
const matches = args.match(/^(\S+)$/); const matches = args.match(/^(\S+)$/);
if (matches) { if (matches) {
@ -729,15 +729,9 @@ export const Commands = [
// Try to find a room with this alias // Try to find a room with this alias
const rooms = cli.getRooms(); const rooms = cli.getRooms();
for (let i = 0; i < rooms.length; i++) { targetRoomId = rooms.find(room => {
if (rooms[i].getCanonicalAlias() === roomAlias || return room.getCanonicalAlias() === roomAlias || room.getAltAliases().includes(roomAlias);
rooms[i].getAltAliases().includes(roomAlias) })?.roomId;
) {
targetRoomId = rooms[i].roomId;
break;
}
if (targetRoomId) break;
}
if (!targetRoomId) { if (!targetRoomId) {
return reject( return reject(
newTranslatableError( newTranslatableError(

View file

@ -39,9 +39,7 @@ export function usersTyping(room: Room, exclude: string[] = []): RoomMember[] {
const whoIsTyping = []; const whoIsTyping = [];
const memberKeys = Object.keys(room.currentState.members); const memberKeys = Object.keys(room.currentState.members);
for (let i = 0; i < memberKeys.length; ++i) { for (const userId of memberKeys) {
const userId = memberKeys[i];
if (room.currentState.members[userId].typing) { if (room.currentState.members[userId].typing) {
if (exclude.indexOf(userId) === -1) { if (exclude.indexOf(userId) === -1) {
whoIsTyping.push(room.currentState.members[userId]); whoIsTyping.push(room.currentState.members[userId]);

View file

@ -524,16 +524,11 @@ export const alwaysAboveLeftOf = (
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
const buttonRight = elementRect.right + window.scrollX; const buttonRight = elementRect.right + window.scrollX;
const buttonBottom = elementRect.bottom + window.scrollY;
const buttonTop = elementRect.top + window.scrollY; const buttonTop = elementRect.top + window.scrollY;
// Align the right edge of the menu to the right edge of the button // Align the right edge of the menu to the right edge of the button
menuOptions.right = UIStore.instance.windowWidth - buttonRight; menuOptions.right = UIStore.instance.windowWidth - buttonRight;
// Align the menu vertically on whichever side of the button has more space available. // Align the menu vertically above the menu
if (buttonBottom < UIStore.instance.windowHeight / 2) { menuOptions.bottom = (UIStore.instance.windowHeight - buttonTop) + vPadding;
menuOptions.top = buttonBottom + vPadding;
} else {
menuOptions.bottom = (UIStore.instance.windowHeight - buttonTop) + vPadding;
}
return menuOptions; return menuOptions;
}; };

View file

@ -546,8 +546,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
private onAction = (payload: ActionPayload): void => { private onAction = (payload: ActionPayload): void => {
// console.log(`MatrixClientPeg.onAction: ${payload.action}`);
// Start the onboarding process for certain actions // Start the onboarding process for certain actions
if (MatrixClientPeg.get()?.isGuest() && ONBOARDING_FLOW_STARTERS.includes(payload.action)) { if (MatrixClientPeg.get()?.isGuest() && ONBOARDING_FLOW_STARTERS.includes(payload.action)) {
// This will cause `payload` to be dispatched later, once a // This will cause `payload` to be dispatched later, once a

View file

@ -101,11 +101,12 @@ export default class RightPanel extends React.Component<IProps, IState> {
if (!this.props.room || member.roomId !== this.props.room.roomId) { if (!this.props.room || member.roomId !== this.props.room.roomId) {
return; return;
} }
// redraw the badge on the membership list // redraw the badge on the membership list
if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) { if (this.state.phase === RightPanelPhases.RoomMemberList) {
this.delayedUpdate(); this.delayedUpdate();
} else if ( } else if (
this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId && this.state.phase === RightPanelPhases.RoomMemberInfo &&
member.userId === this.state.cardState.member.userId member.userId === this.state.cardState.member.userId
) { ) {
// refresh the member info (e.g. new power level) // refresh the member info (e.g. new power level)

View file

@ -2293,7 +2293,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
highlightedEventId = this.state.initialEventId; highlightedEventId = this.state.initialEventId;
} }
// console.info("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview);
const messagePanel = ( const messagePanel = (
<TimelinePanel <TimelinePanel
ref={this.gatherTimelinePanelRef} ref={this.gatherTimelinePanelRef}

View file

@ -608,6 +608,11 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
}; };
} }
let buttonText = _t("Saving...");
if (!saving) {
buttonText = selectionAllSuggested ? _t("Mark as not suggested") : _t("Mark as suggested");
}
return <> return <>
<Button <Button
{...props} {...props}
@ -669,10 +674,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
kind="primary_outline" kind="primary_outline"
disabled={disabled} disabled={disabled}
> >
{ saving { buttonText }
? _t("Saving...")
: (selectionAllSuggested ? _t("Mark as not suggested") : _t("Mark as suggested"))
}
</Button> </Button>
</>; </>;
}; };

View file

@ -477,8 +477,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
ev.preventDefault(); ev.preventDefault();
if (busy) return; if (busy) return;
setError(""); setError("");
for (let i = 0; i < fieldRefs.length; i++) { for (const fieldRef of fieldRefs) {
const fieldRef = fieldRefs[i];
const valid = await fieldRef.current.validate({ allowEmpty: true }); const valid = await fieldRef.current.validate({ allowEmpty: true });
if (valid === false) { // true/null are allowed if (valid === false) { // true/null are allowed

View file

@ -645,8 +645,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
if (data.timeline.getTimelineSet() !== this.props.timelineSet) return; if (data.timeline.getTimelineSet() !== this.props.timelineSet) return;
if (!Thread.hasServerSideSupport && this.context.timelineRenderingType === TimelineRenderingType.Thread) { if (!Thread.hasServerSideSupport && this.context.timelineRenderingType === TimelineRenderingType.Thread) {
// const direction = toStartOfTimeline ? Direction.Backward : Direction.Forward;
// this.timelineWindow.extend(direction, 1);
if (toStartOfTimeline && !this.state.canBackPaginate) { if (toStartOfTimeline && !this.state.canBackPaginate) {
this.setState({ this.setState({
canBackPaginate: true, canBackPaginate: true,

View file

@ -191,14 +191,8 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
return false; return false;
} }
private allFieldsValid() { private allFieldsValid(): boolean {
const keys = Object.keys(this.state.fieldValid); return Object.values(this.state.fieldValid).every(Boolean);
for (let i = 0; i < keys.length; ++i) {
if (!this.state.fieldValid[keys[i]]) {
return false;
}
}
return true;
} }
private findFirstInvalidField(fieldIDs: LoginField[]) { private findFirstInvalidField(fieldIDs: LoginField[]) {

View file

@ -224,14 +224,8 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
/** /**
* @returns {boolean} true if all fields were valid last time they were validated. * @returns {boolean} true if all fields were valid last time they were validated.
*/ */
private allFieldsValid() { private allFieldsValid(): boolean {
const keys = Object.keys(this.state.fieldValid); return Object.values(this.state.fieldValid).every(Boolean);
for (let i = 0; i < keys.length; ++i) {
if (!this.state.fieldValid[keys[i]]) {
return false;
}
}
return true;
} }
private findFirstInvalidField(fieldIDs: RegistrationField[]) { private findFirstInvalidField(fieldIDs: RegistrationField[]) {

View file

@ -166,10 +166,8 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
if (otherUserId && this.props.room.getJoinedMemberCount() === 2) { if (otherUserId && this.props.room.getJoinedMemberCount() === 2) {
// Track presence, if available // Track presence, if available
if (isPresenceEnabled()) { if (isPresenceEnabled()) {
if (otherUserId) { this.dmUser = MatrixClientPeg.get().getUser(otherUserId);
this.dmUser = MatrixClientPeg.get().getUser(otherUserId); icon = this.getPresenceIcon();
icon = this.getPresenceIcon();
}
} }
} else { } else {
// Track publicity // Track publicity

View file

@ -181,7 +181,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
setError(null); setError(null);
setProgress(0); setProgress(0);
let error; let error: Error | undefined;
for (const room of selectedToAdd) { for (const room of selectedToAdd) {
const via = calculateRoomVia(room); const via = calculateRoomVia(room);
@ -197,13 +197,15 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
setProgress(i => i + 1); setProgress(i => i + 1);
} catch (e) { } catch (e) {
logger.error("Failed to add rooms to space", e); logger.error("Failed to add rooms to space", e);
setError(error = e); error = e;
break; break;
} }
} }
if (!error) { if (!error) {
onFinished(true); onFinished(true);
} else {
setError(error);
} }
}; };

View file

@ -128,9 +128,6 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
this.nameField.current.focus(); this.nameField.current.focus();
} }
componentWillUnmount() {
}
private onKeyDown = (event: KeyboardEvent) => { private onKeyDown = (event: KeyboardEvent) => {
const action = getKeyBindingsManager().getAccessibilityAction(event); const action = getKeyBindingsManager().getAccessibilityAction(event);
switch (action) { switch (action) {

View file

@ -92,12 +92,13 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({
/> />
</div>); </div>);
} else { } else {
let text = _t("Upload completed");
if (!success) {
text = cancelled ? _t("Cancelled signature upload") : _t("Unable to upload");
}
body = (<div> body = (<div>
{ success ? <span>{ text }</span>
<span>{ _t("Upload completed") }</span> :
cancelled ?
<span>{ _t("Cancelled signature upload") }</span> :
<span>{ _t("Unable to upload") }</span> }
<DialogButtons <DialogButtons
primaryButton={_t("OK")} primaryButton={_t("OK")}
hasCancel={false} hasCancel={false}

View file

@ -61,7 +61,7 @@ type DynamicElementProps<T extends keyof JSX.IntrinsicElements> =
type IProps<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & { type IProps<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
inputRef?: React.Ref<Element>; inputRef?: React.Ref<Element>;
element?: T; element?: T;
children?: ReactNode | undefined; children?: ReactNode;
// The kind of button, similar to how Bootstrap works. // The kind of button, similar to how Bootstrap works.
// See available classes for AccessibleButton for options. // See available classes for AccessibleButton for options.
kind?: AccessibleButtonKind | string; kind?: AccessibleButtonKind | string;

View file

@ -117,8 +117,6 @@ export default class EditableText extends React.Component<IProps, IState> {
}; };
private onKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>): void => { private onKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>): void => {
// console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
if (this.placeholder) { if (this.placeholder) {
this.showPlaceholder(false); this.showPlaceholder(false);
} }
@ -130,13 +128,9 @@ export default class EditableText extends React.Component<IProps, IState> {
ev.preventDefault(); ev.preventDefault();
break; break;
} }
// console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
}; };
private onKeyUp = (ev: React.KeyboardEvent<HTMLDivElement>): void => { private onKeyUp = (ev: React.KeyboardEvent<HTMLDivElement>): void => {
// console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
if (!(ev.target as HTMLDivElement).textContent) { if (!(ev.target as HTMLDivElement).textContent) {
this.showPlaceholder(true); this.showPlaceholder(true);
} else if (!this.placeholder) { } else if (!this.placeholder) {
@ -152,8 +146,6 @@ export default class EditableText extends React.Component<IProps, IState> {
this.onFinish(ev); this.onFinish(ev);
break; break;
} }
// console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
}; };
private onClickDiv = (): void => { private onClickDiv = (): void => {
@ -165,8 +157,6 @@ export default class EditableText extends React.Component<IProps, IState> {
}; };
private onFocus = (ev: React.FocusEvent<HTMLDivElement>): void => { private onFocus = (ev: React.FocusEvent<HTMLDivElement>): void => {
//ev.target.setSelectionRange(0, ev.target.textContent.length);
const node = ev.target.childNodes[0]; const node = ev.target.childNodes[0];
if (node) { if (node) {
const range = document.createRange(); const range = document.createRange();

View file

@ -215,12 +215,12 @@ export default class EventListSummary extends React.Component<IProps> {
repeats: number; repeats: number;
}[] = []; }[] = [];
for (let i = 0; i < transitions.length; i++) { for (const transition of transitions) {
if (res.length > 0 && res[res.length - 1].transitionType === transitions[i]) { if (res.length > 0 && res[res.length - 1].transitionType === transition) {
res[res.length - 1].repeats += 1; res[res.length - 1].repeats += 1;
} else { } else {
res.push({ res.push({
transitionType: transitions[i], transitionType: transition,
repeats: 1, repeats: 1,
}); });
} }
@ -399,7 +399,6 @@ export default class EventListSummary extends React.Component<IProps> {
} else if (e.mxEvent.getContent().avatar_url !== e.mxEvent.getPrevContent().avatar_url) { } else if (e.mxEvent.getContent().avatar_url !== e.mxEvent.getPrevContent().avatar_url) {
return TransitionType.ChangedAvatar; return TransitionType.ChangedAvatar;
} }
// console.log("MELS ignoring duplicate membership join event");
return TransitionType.NoChange; return TransitionType.NoChange;
} else { } else {
return TransitionType.Joined; return TransitionType.Joined;

View file

@ -171,48 +171,52 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
); );
}; };
let map: JSX.Element;
if (displayStatus === BeaconDisplayStatus.Active && !isMapDisplayError) {
map = <Map
id={mapId}
centerGeoUri={latestLocationState.uri}
onError={setError}
onClick={onClick}
className="mx_MBeaconBody_map"
>
{
({ map }) =>
<SmartMarker
map={map}
id={`${mapId}-marker`}
geoUri={latestLocationState.uri}
roomMember={markerRoomMember}
useMemberColor
/>
}
</Map>;
} else if (isMapDisplayError) {
map = <MapError
error={error.message as LocationShareError}
onClick={onClick}
className={classNames(
'mx_MBeaconBody_mapError',
// set interactive class when maximised map can be opened
{ 'mx_MBeaconBody_mapErrorInteractive':
displayStatus === BeaconDisplayStatus.Active,
},
)}
isMinimised
/>;
} else {
map = <MapFallback
isLoading={displayStatus === BeaconDisplayStatus.Loading}
className='mx_MBeaconBody_map mx_MBeaconBody_mapFallback'
/>;
}
return ( return (
<div <div
className='mx_MBeaconBody' className='mx_MBeaconBody'
ref={ref} ref={ref}
> >
{ (displayStatus === BeaconDisplayStatus.Active && !isMapDisplayError) ? { map }
<Map
id={mapId}
centerGeoUri={latestLocationState.uri}
onError={setError}
onClick={onClick}
className="mx_MBeaconBody_map"
>
{
({ map }) =>
<SmartMarker
map={map}
id={`${mapId}-marker`}
geoUri={latestLocationState.uri}
roomMember={markerRoomMember}
useMemberColor
/>
}
</Map>
: isMapDisplayError ?
<MapError
error={error.message as LocationShareError}
onClick={onClick}
className={classNames(
'mx_MBeaconBody_mapError',
// set interactive class when maximised map can be opened
{ 'mx_MBeaconBody_mapErrorInteractive':
displayStatus === BeaconDisplayStatus.Active,
},
)}
isMinimised
/> :
<MapFallback
isLoading={displayStatus === BeaconDisplayStatus.Loading}
className='mx_MBeaconBody_map mx_MBeaconBody_mapFallback'
/>
}
{ isOwnBeacon ? { isOwnBeacon ?
<OwnBeaconStatus <OwnBeaconStatus
className='mx_MBeaconBody_chin' className='mx_MBeaconBody_chin'

View file

@ -88,9 +88,9 @@ export function computedStyle(element: HTMLElement) {
if (cssText == "") { if (cssText == "") {
// Firefox doesn't implement ".cssText" for computed styles. // Firefox doesn't implement ".cssText" for computed styles.
// https://bugzilla.mozilla.org/show_bug.cgi?id=137687 // https://bugzilla.mozilla.org/show_bug.cgi?id=137687
for (let i = 0; i < style.length; i++) { for (const rule of style) {
cssText += style[i] + ":"; cssText += rule + ":";
cssText += style.getPropertyValue(style[i]) + ";"; cssText += style.getPropertyValue(rule) + ";";
} }
} }
return cssText; return cssText;

View file

@ -146,7 +146,7 @@ function useHasCrossSigningKeys(cli: MatrixClient, member: User, canVerify: bool
} finally { } finally {
setUpdating(false); setUpdating(false);
} }
}, [cli, member, canVerify], undefined); }, [cli, member, canVerify]);
} }
function DeviceItem({ userId, device }: { userId: string, device: IDevice }) { function DeviceItem({ userId, device }: { userId: string, device: IDevice }) {

View file

@ -119,7 +119,6 @@ export default class MemberList extends React.Component<IProps, IState> {
cli.on(UserEvent.LastPresenceTs, this.onUserPresenceChange); cli.on(UserEvent.LastPresenceTs, this.onUserPresenceChange);
cli.on(UserEvent.Presence, this.onUserPresenceChange); cli.on(UserEvent.Presence, this.onUserPresenceChange);
cli.on(UserEvent.CurrentlyActive, this.onUserPresenceChange); cli.on(UserEvent.CurrentlyActive, this.onUserPresenceChange);
// cli.on("Room.timeline", this.onRoomTimeline);
} }
componentWillUnmount() { componentWillUnmount() {
@ -199,7 +198,6 @@ export default class MemberList extends React.Component<IProps, IState> {
// member tile and re-render it. This is more efficient than every tile // member tile and re-render it. This is more efficient than every tile
// ever attaching their own listener. // ever attaching their own listener.
const tile = this.refs[user.userId]; const tile = this.refs[user.userId];
// console.log(`Got presence update for ${user.userId}. hasTile=${!!tile}`);
if (tile) { if (tile) {
this.updateList(); // reorder the membership list this.updateList(); // reorder the membership list
} }
@ -370,14 +368,9 @@ export default class MemberList extends React.Component<IProps, IState> {
// ...and then alphabetically. // ...and then alphabetically.
// We could tiebreak instead by "last recently spoken in this room" if we wanted to. // We could tiebreak instead by "last recently spoken in this room" if we wanted to.
// console.log(`Comparing userA=${this.memberString(memberA)} userB=${this.memberString(memberB)}`);
const userA = memberA.user; const userA = memberA.user;
const userB = memberB.user; const userB = memberB.user;
// if (!userA) console.log("!! MISSING USER FOR A-SIDE: " + memberA.name + " !!");
// if (!userB) console.log("!! MISSING USER FOR B-SIDE: " + memberB.name + " !!");
if (!userA && !userB) return 0; if (!userA && !userB) return 0;
if (userA && !userB) return -1; if (userA && !userB) return -1;
if (!userA && userB) return 1; if (!userA && userB) return 1;
@ -393,22 +386,18 @@ export default class MemberList extends React.Component<IProps, IState> {
const idxA = presenceIndex(userA.currentlyActive ? 'active' : userA.presence); const idxA = presenceIndex(userA.currentlyActive ? 'active' : userA.presence);
const idxB = presenceIndex(userB.currentlyActive ? 'active' : userB.presence); const idxB = presenceIndex(userB.currentlyActive ? 'active' : userB.presence);
// console.log(`userA_presenceGroup=${idxA} userB_presenceGroup=${idxB}`);
if (idxA !== idxB) { if (idxA !== idxB) {
// console.log("Comparing on presence group - returning");
return idxA - idxB; return idxA - idxB;
} }
} }
// Second by power level // Second by power level
if (memberA.powerLevel !== memberB.powerLevel) { if (memberA.powerLevel !== memberB.powerLevel) {
// console.log("Comparing on power level - returning");
return memberB.powerLevel - memberA.powerLevel; return memberB.powerLevel - memberA.powerLevel;
} }
// Third by last active // Third by last active
if (this.showPresence && userA.getLastActiveTs() !== userB.getLastActiveTs()) { if (this.showPresence && userA.getLastActiveTs() !== userB.getLastActiveTs()) {
// console.log("Comparing on last active timestamp - returning");
return userB.getLastActiveTs() - userA.getLastActiveTs(); return userB.getLastActiveTs() - userA.getLastActiveTs();
} }

View file

@ -274,7 +274,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
}; };
private onListsUpdated = () => { private onListsUpdated = () => {
const stateUpdates: IState & any = {}; // &any is to avoid a cast on the initializer const stateUpdates = {} as IState;
const currentRooms = this.state.rooms; const currentRooms = this.state.rooms;
const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []); const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []);

View file

@ -353,13 +353,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
} }
private allFieldsValid(): boolean { private allFieldsValid(): boolean {
const keys = Object.keys(this.state.fieldValid); return Object.values(this.state.fieldValid).every(Boolean);
for (let i = 0; i < keys.length; ++i) {
if (!this.state.fieldValid[keys[i]]) {
return false;
}
}
return true;
} }
private findFirstInvalidField(fieldIDs: string[]): Field { private findFirstInvalidField(fieldIDs: string[]): Field {

View file

@ -50,7 +50,7 @@ export default class InlineTermsAgreement extends React.Component<IProps, IState
public componentDidMount(): void { public componentDidMount(): void {
// Build all the terms the user needs to accept // Build all the terms the user needs to accept
const policies = []; // { checked, url, name } const policies: Policy[] = [];
for (const servicePolicies of this.props.policiesAndServicePairs) { for (const servicePolicies of this.props.policiesAndServicePairs) {
const availablePolicies = Object.values(servicePolicies.policies); const availablePolicies = Object.values(servicePolicies.policies);
for (const policy of availablePolicies) { for (const policy of availablePolicies) {

View file

@ -3331,10 +3331,10 @@
"This room is suggested as a good one to join": "This room is suggested as a good one to join", "This room is suggested as a good one to join": "This room is suggested as a good one to join",
"Suggested": "Suggested", "Suggested": "Suggested",
"Select a room below first": "Select a room below first", "Select a room below first": "Select a room below first",
"Failed to remove some rooms. Try again later": "Failed to remove some rooms. Try again later",
"Removing...": "Removing...",
"Mark as not suggested": "Mark as not suggested", "Mark as not suggested": "Mark as not suggested",
"Mark as suggested": "Mark as suggested", "Mark as suggested": "Mark as suggested",
"Failed to remove some rooms. Try again later": "Failed to remove some rooms. Try again later",
"Removing...": "Removing...",
"Failed to load list of rooms.": "Failed to load list of rooms.", "Failed to load list of rooms.": "Failed to load list of rooms.",
"Your server does not support showing space hierarchies.": "Your server does not support showing space hierarchies.", "Your server does not support showing space hierarchies.": "Your server does not support showing space hierarchies.",
"You may want to try a different search or check for typos.": "You may want to try a different search or check for typos.", "You may want to try a different search or check for typos.": "You may want to try a different search or check for typos.",

View file

@ -195,4 +195,34 @@ describe('SlashCommands', () => {
}); });
}); });
}); });
describe("/part", () => {
it("should part room matching alias if found", async () => {
const room1 = new Room("room-id", client, client.getUserId());
room1.getCanonicalAlias = jest.fn().mockReturnValue("#foo:bar");
const room2 = new Room("other-room", client, client.getUserId());
room2.getCanonicalAlias = jest.fn().mockReturnValue("#baz:bar");
mocked(client.getRooms).mockReturnValue([room1, room2]);
const command = getCommand("/part #foo:bar");
expect(command.cmd).toBeDefined();
expect(command.args).toBeDefined();
await command.cmd.run("room-id", null, command.args);
expect(client.leaveRoomChain).toHaveBeenCalledWith("room-id", expect.anything());
});
it("should part room matching alt alias if found", async () => {
const room1 = new Room("room-id", client, client.getUserId());
room1.getAltAliases = jest.fn().mockReturnValue(["#foo:bar"]);
const room2 = new Room("other-room", client, client.getUserId());
room2.getAltAliases = jest.fn().mockReturnValue(["#baz:bar"]);
mocked(client.getRooms).mockReturnValue([room1, room2]);
const command = getCommand("/part #foo:bar");
expect(command.cmd).toBeDefined();
expect(command.args).toBeDefined();
await command.cmd.run("room-id", null, command.args);
expect(client.leaveRoomChain).toHaveBeenCalledWith("room-id", expect.anything());
});
});
}); });

View file

@ -187,6 +187,7 @@ export function createTestClient(): MatrixClient {
} as unknown as MediaHandler), } as unknown as MediaHandler),
uploadContent: jest.fn(), uploadContent: jest.fn(),
getEventMapper: () => (opts) => new MatrixEvent(opts), getEventMapper: () => (opts) => new MatrixEvent(opts),
leaveRoomChain: jest.fn(roomId => ({ [roomId]: null })),
} as unknown as MatrixClient; } as unknown as MatrixClient;
client.reEmitter = new ReEmitter(client); client.reEmitter = new ReEmitter(client);