Make SonarCloud happier (#9545)
* Make SonarCloud happier * i18n * Iterate * Update AddExistingToSpaceDialog.tsx * Update SlashCommands.tsx
This commit is contained in:
parent
77764d80bc
commit
3747464b41
33 changed files with 131 additions and 162 deletions
|
@ -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
|
||||||
|
|
12
src/Login.ts
12
src/Login.ts
|
@ -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>> {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
</>;
|
</>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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[]) {
|
||||||
|
|
|
@ -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[]) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 }) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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] || []);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.",
|
||||||
|
|
|
@ -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());
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue