diff --git a/CHANGELOG.md b/CHANGELOG.md
index d459b4e94a..58d23e3413 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,115 @@
+Changes in [3.20.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0) (2021-05-10)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.20.0-rc.1...v3.20.0)
+
+ * Upgrade to JS SDK 10.1.0
+ * [Release] Don't use the event's metadata to calc the scale of an image
+ [\#6004](https://github.com/matrix-org/matrix-react-sdk/pull/6004)
+
+Changes in [3.20.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0-rc.1) (2021-05-04)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0...v3.20.0-rc.1)
+
+ * Upgrade to JS SDK 10.1.0-rc.1
+ * Translations update from Weblate
+ [\#5966](https://github.com/matrix-org/matrix-react-sdk/pull/5966)
+ * Fix more space panel layout and hover behaviour issues
+ [\#5965](https://github.com/matrix-org/matrix-react-sdk/pull/5965)
+ * Fix edge case with space panel alignment with subspaces on ff
+ [\#5964](https://github.com/matrix-org/matrix-react-sdk/pull/5964)
+ * Fix saving room pill part to history
+ [\#5951](https://github.com/matrix-org/matrix-react-sdk/pull/5951)
+ * Generate room preview even when minimized
+ [\#5948](https://github.com/matrix-org/matrix-react-sdk/pull/5948)
+ * Another change from recovery passphrase to Security Phrase
+ [\#5934](https://github.com/matrix-org/matrix-react-sdk/pull/5934)
+ * Sort rooms in the add existing to space dialog based on recency
+ [\#5943](https://github.com/matrix-org/matrix-react-sdk/pull/5943)
+ * Inhibit sending RR when context switching to a room
+ [\#5944](https://github.com/matrix-org/matrix-react-sdk/pull/5944)
+ * Prevent room list keyboard handling from landing focus on hidden nodes
+ [\#5950](https://github.com/matrix-org/matrix-react-sdk/pull/5950)
+ * Make the text filter search all spaces instead of just the selected one
+ [\#5942](https://github.com/matrix-org/matrix-react-sdk/pull/5942)
+ * Enable indent rule and fix indent
+ [\#5931](https://github.com/matrix-org/matrix-react-sdk/pull/5931)
+ * Prevent peeking members from reacting
+ [\#5946](https://github.com/matrix-org/matrix-react-sdk/pull/5946)
+ * Disallow inline display maths
+ [\#5939](https://github.com/matrix-org/matrix-react-sdk/pull/5939)
+ * Space creation prompt user to add existing rooms for "Just Me" spaces
+ [\#5923](https://github.com/matrix-org/matrix-react-sdk/pull/5923)
+ * Add test coverage collection script
+ [\#5937](https://github.com/matrix-org/matrix-react-sdk/pull/5937)
+ * Fix joining room using via servers regression
+ [\#5936](https://github.com/matrix-org/matrix-react-sdk/pull/5936)
+ * Revert "Fixes the two Todays problem in Redaction"
+ [\#5938](https://github.com/matrix-org/matrix-react-sdk/pull/5938)
+ * Handle encoded matrix URLs
+ [\#5903](https://github.com/matrix-org/matrix-react-sdk/pull/5903)
+ * Render ignored users setting regardless of if there are any
+ [\#5860](https://github.com/matrix-org/matrix-react-sdk/pull/5860)
+ * Fix inserting trailing colon after mention/pill
+ [\#5830](https://github.com/matrix-org/matrix-react-sdk/pull/5830)
+ * Fixes the two Todays problem in Redaction
+ [\#5917](https://github.com/matrix-org/matrix-react-sdk/pull/5917)
+ * Fix page up/down scrolling only half a page
+ [\#5920](https://github.com/matrix-org/matrix-react-sdk/pull/5920)
+ * Voice messages: Composer controls
+ [\#5935](https://github.com/matrix-org/matrix-react-sdk/pull/5935)
+ * Support MSC3086 asserted identity
+ [\#5886](https://github.com/matrix-org/matrix-react-sdk/pull/5886)
+ * Handle possible edge case with getting stuck in "unsent messages" bar
+ [\#5930](https://github.com/matrix-org/matrix-react-sdk/pull/5930)
+ * Fix suggested rooms not showing up regression from room list optimisation
+ [\#5932](https://github.com/matrix-org/matrix-react-sdk/pull/5932)
+ * Broadcast language change to ElectronPlatform
+ [\#5913](https://github.com/matrix-org/matrix-react-sdk/pull/5913)
+ * Fix VoIP PIP frame color
+ [\#5701](https://github.com/matrix-org/matrix-react-sdk/pull/5701)
+ * Convert some Flow-typed files to TypeScript
+ [\#5912](https://github.com/matrix-org/matrix-react-sdk/pull/5912)
+ * Initial SpaceStore tests work
+ [\#5906](https://github.com/matrix-org/matrix-react-sdk/pull/5906)
+ * Fix issues with space hierarchy in layout and with incompatible servers
+ [\#5926](https://github.com/matrix-org/matrix-react-sdk/pull/5926)
+ * Scale all mxc thumbs using device pixel ratio for hidpi
+ [\#5928](https://github.com/matrix-org/matrix-react-sdk/pull/5928)
+ * Fix add existing to space dialog no longer showing rooms for public spaces
+ [\#5918](https://github.com/matrix-org/matrix-react-sdk/pull/5918)
+ * Disable spaces context switching for when exploring a space
+ [\#5924](https://github.com/matrix-org/matrix-react-sdk/pull/5924)
+ * Autofocus search box in the add existing to space dialog
+ [\#5921](https://github.com/matrix-org/matrix-react-sdk/pull/5921)
+ * Use label element in add existing to space dialog for easier hit target
+ [\#5922](https://github.com/matrix-org/matrix-react-sdk/pull/5922)
+ * Dynamic max and min zoom in the new ImageView
+ [\#5916](https://github.com/matrix-org/matrix-react-sdk/pull/5916)
+ * Improve message error states
+ [\#5897](https://github.com/matrix-org/matrix-react-sdk/pull/5897)
+ * Check for null room in `VisibilityProvider`
+ [\#5914](https://github.com/matrix-org/matrix-react-sdk/pull/5914)
+ * Add unit tests for various collection-based utility functions
+ [\#5910](https://github.com/matrix-org/matrix-react-sdk/pull/5910)
+ * Spaces visual fixes
+ [\#5909](https://github.com/matrix-org/matrix-react-sdk/pull/5909)
+ * Remove reliance on DOM API to generated message preview
+ [\#5908](https://github.com/matrix-org/matrix-react-sdk/pull/5908)
+ * Expand upon voice message event & include overall waveform
+ [\#5888](https://github.com/matrix-org/matrix-react-sdk/pull/5888)
+ * Use floats for image background opacity
+ [\#5905](https://github.com/matrix-org/matrix-react-sdk/pull/5905)
+ * Show invites to spaces at the top of the space panel
+ [\#5902](https://github.com/matrix-org/matrix-react-sdk/pull/5902)
+ * Improve edge cases with spaces context switching
+ [\#5899](https://github.com/matrix-org/matrix-react-sdk/pull/5899)
+ * Fix spaces notification dots wrongly including upgraded (hidden) rooms
+ [\#5900](https://github.com/matrix-org/matrix-react-sdk/pull/5900)
+ * Iterate the spaces face pile design
+ [\#5898](https://github.com/matrix-org/matrix-react-sdk/pull/5898)
+ * Fix alignment issue with nested spaces being cut off wrong
+ [\#5890](https://github.com/matrix-org/matrix-react-sdk/pull/5890)
+
Changes in [3.19.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.19.0) (2021-04-26)
=====================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0-rc.1...v3.19.0)
diff --git a/package.json b/package.json
index be195e2e9e..342591081f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.19.0",
+ "version": "3.20.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@@ -97,7 +97,7 @@
"react-transition-group": "^4.4.1",
"resize-observer-polyfill": "^1.5.1",
"rfc4648": "^1.4.0",
- "sanitize-html": "github:apostrophecms/sanitize-html#3c7f93f2058f696f5359e3e58d464161647226db",
+ "sanitize-html": "^2.3.2",
"tar-js": "^0.3.0",
"text-encoding-utf-8": "^1.0.2",
"url": "^0.11.0",
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index c93f07fa0f..e5e0065be8 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -544,11 +544,13 @@ export default class MessagePanel extends React.Component {
}
if (!grouper) {
const wantTile = this._shouldShowEvent(mxEv);
+ const isGrouped = false;
if (wantTile) {
// make sure we unpack the array returned by _getTilesForEvent,
// otherwise react will auto-generate keys and we will end up
// replacing all of the DOM elements every time we paginate.
- ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, nextEvent, nextTile));
+ ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, isGrouped,
+ nextEvent, nextTile));
prevEvent = mxEv;
}
@@ -564,7 +566,7 @@ export default class MessagePanel extends React.Component {
return ret;
}
- _getTilesForEvent(prevEvent, mxEv, last, nextEvent, nextEventWithTile) {
+ _getTilesForEvent(prevEvent, mxEv, last, isGrouped=false, nextEvent, nextEventWithTile) {
const TileErrorBoundary = sdk.getComponent('messages.TileErrorBoundary');
const EventTile = sdk.getComponent('rooms.EventTile');
const DateSeparator = sdk.getComponent('messages.DateSeparator');
@@ -584,7 +586,7 @@ export default class MessagePanel extends React.Component {
// do we need a date separator since the last event?
const wantsDateSeparator = this._wantsDateSeparator(prevEvent, eventDate);
- if (wantsDateSeparator) {
+ if (wantsDateSeparator && !isGrouped) {
const dateSeparator =
;
ret.push(dateSeparator);
}
@@ -968,9 +970,9 @@ class CreationGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventListSummary = sdk.getComponent('views.elements.EventListSummary');
-
const panel = this.panel;
const ret = [];
+ const isGrouped = true;
const createEvent = this.createEvent;
const lastShownEvent = this.lastShownEvent;
@@ -984,12 +986,12 @@ class CreationGrouper {
// If this m.room.create event should be shown (room upgrade) then show it before the summary
if (panel._shouldShowEvent(createEvent)) {
// pass in the createEvent as prevEvent as well so no extra DateSeparator is rendered
- ret.push(...panel._getTilesForEvent(createEvent, createEvent, false));
+ ret.push(...panel._getTilesForEvent(createEvent, createEvent));
}
for (const ejected of this.ejectedEvents) {
ret.push(...panel._getTilesForEvent(
- createEvent, ejected, createEvent === lastShownEvent,
+ createEvent, ejected, createEvent === lastShownEvent, isGrouped,
));
}
@@ -998,7 +1000,7 @@ class CreationGrouper {
// of EventListSummary, render each member event as if the previous
// one was itself. This way, the timestamp of the previous event === the
// timestamp of the current event, and no DateSeparator is inserted.
- return panel._getTilesForEvent(e, e, e === lastShownEvent);
+ return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped);
}).reduce((a, b) => a.concat(b), []);
// Get sender profile from the latest event in the summary as the m.room.create doesn't contain one
const ev = this.events[this.events.length - 1];
@@ -1083,7 +1085,7 @@ class RedactionGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventListSummary = sdk.getComponent('views.elements.EventListSummary');
-
+ const isGrouped = true;
const panel = this.panel;
const ret = [];
const lastShownEvent = this.lastShownEvent;
@@ -1103,7 +1105,8 @@ class RedactionGrouper {
let eventTiles = this.events.map((e, i) => {
senders.add(e.sender);
const prevEvent = i === 0 ? this.prevEvent : this.events[i - 1];
- return panel._getTilesForEvent(prevEvent, e, e === lastShownEvent, this.nextEvent, this.nextEventTile);
+ return panel._getTilesForEvent(
+ prevEvent, e, e === lastShownEvent, isGrouped, this.nextEvent, this.nextEventTile);
}).reduce((a, b) => a.concat(b), []);
if (eventTiles.length === 0) {
@@ -1182,7 +1185,7 @@ class MemberGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
-
+ const isGrouped = true;
const panel = this.panel;
const lastShownEvent = this.lastShownEvent;
const ret = [];
@@ -1215,7 +1218,7 @@ class MemberGrouper {
// of MemberEventListSummary, render each member event as if the previous
// one was itself. This way, the timestamp of the previous event === the
// timestamp of the current event, and no DateSeparator is inserted.
- return panel._getTilesForEvent(e, e, e === lastShownEvent);
+ return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped);
}).reduce((a, b) => a.concat(b), []);
if (eventTiles.length === 0) {
diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx
index 34682877e0..bda46aef07 100644
--- a/src/components/structures/RoomSearch.tsx
+++ b/src/components/structures/RoomSearch.tsx
@@ -27,8 +27,8 @@ import { Action } from "../../dispatcher/actions";
import RoomListStore from "../../stores/room-list/RoomListStore";
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
-import {replaceableComponent} from "../../utils/replaceableComponent";
-import SpaceStore, {UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES} from "../../stores/SpaceStore";
+import { replaceableComponent } from "../../utils/replaceableComponent";
+import SpaceStore, { UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES } from "../../stores/SpaceStore";
interface IProps {
isMinimized: boolean;
diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx
index 05d487a9eb..f736736acc 100644
--- a/src/components/views/elements/ImageView.tsx
+++ b/src/components/views/elements/ImageView.tsx
@@ -108,8 +108,6 @@ export default class ImageView extends React.Component {
window.addEventListener("resize", this.calculateZoom);
// After the image loads for the first time we want to calculate the zoom
this.image.current.addEventListener("load", this.calculateZoom);
- // Try to precalculate the zoom from width and height props
- this.calculateZoom();
}
componentWillUnmount() {
@@ -122,11 +120,8 @@ export default class ImageView extends React.Component {
const image = this.image.current;
const imageWrapper = this.imageWrapper.current;
- const width = this.props.width || image.naturalWidth;
- const height = this.props.height || image.naturalHeight;
-
- const zoomX = imageWrapper.clientWidth / width;
- const zoomY = imageWrapper.clientHeight / height;
+ const zoomX = imageWrapper.clientWidth / image.naturalWidth;
+ const zoomY = imageWrapper.clientHeight / image.naturalHeight;
// If the image is smaller in both dimensions set its the zoom to 1 to
// display it in its original size
diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx
index 2fa5fd89d3..faf8860cad 100644
--- a/src/components/views/right_panel/UserInfo.tsx
+++ b/src/components/views/right_panel/UserInfo.tsx
@@ -187,9 +187,15 @@ function DeviceItem({userId, device}: {userId: string, device: IDevice}) {
verifyDevice(cli.getUser(userId), device);
};
- const deviceName = device.ambiguous ?
- (device.getDisplayName() ? device.getDisplayName() : "") + " (" + device.deviceId + ")" :
- device.getDisplayName();
+ let deviceName;
+ if (!device.getDisplayName()?.trim()) {
+ deviceName = device.deviceId;
+ } else {
+ deviceName = device.ambiguous ?
+ device.getDisplayName() + " (" + device.deviceId + ")" :
+ device.getDisplayName();
+ }
+
let trustedLabel = null;
if (userTrust.isVerified()) trustedLabel = isVerified ? _t("Trusted") : _t("Not trusted");
diff --git a/src/components/views/rooms/EditMessageComposer.js b/src/components/views/rooms/EditMessageComposer.js
index b006fe8c8d..c0b60a3247 100644
--- a/src/components/views/rooms/EditMessageComposer.js
+++ b/src/components/views/rooms/EditMessageComposer.js
@@ -16,7 +16,7 @@ limitations under the License.
*/
import React from 'react';
import * as sdk from '../../../index';
-import {_t} from '../../../languageHandler';
+import {_t, _td} from '../../../languageHandler';
import PropTypes from 'prop-types';
import dis from '../../../dispatcher/dispatcher';
import EditorModel from '../../../editor/model';
@@ -24,16 +24,18 @@ import {getCaretOffsetAndText} from '../../../editor/dom';
import {htmlSerializeIfNeeded, textSerialize, containsEmote, stripEmoteCommand} from '../../../editor/serialize';
import {findEditableEvent} from '../../../utils/EventUtils';
import {parseEvent} from '../../../editor/deserialize';
-import {PartCreator} from '../../../editor/parts';
+import {CommandPartCreator} from '../../../editor/parts';
import EditorStateTransfer from '../../../utils/EditorStateTransfer';
import classNames from 'classnames';
import {EventStatus} from 'matrix-js-sdk/src/models/event';
import BasicMessageComposer from "./BasicMessageComposer";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
+import {CommandCategories, getCommand} from '../../../SlashCommands';
import {Action} from "../../../dispatcher/actions";
import CountlyAnalytics from "../../../CountlyAnalytics";
import {getKeyBindingsManager, MessageComposerAction} from '../../../KeyBindingsManager';
import {replaceableComponent} from "../../../utils/replaceableComponent";
+import Modal from '../../../Modal';
function _isReply(mxEvent) {
const relatesTo = mxEvent.getContent()["m.relates_to"];
@@ -178,6 +180,22 @@ export default class EditMessageComposer extends React.Component {
dis.fire(Action.FocusComposer);
}
+ _isSlashCommand() {
+ const parts = this.model.parts;
+ const firstPart = parts[0];
+ if (firstPart) {
+ if (firstPart.type === "command" && firstPart.text.startsWith("/") && !firstPart.text.startsWith("//")) {
+ return true;
+ }
+
+ if (firstPart.text.startsWith("/") && !firstPart.text.startsWith("//")
+ && (firstPart.type === "plain" || firstPart.type === "pill-candidate")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
_isContentModified(newContent) {
// if nothing has changed then bail
const oldContent = this.props.editState.getEvent().getContent();
@@ -190,19 +208,112 @@ export default class EditMessageComposer extends React.Component {
return true;
}
- _sendEdit = () => {
+ _getSlashCommand() {
+ const commandText = this.model.parts.reduce((text, part) => {
+ // use mxid to textify user pills in a command
+ if (part.type === "user-pill") {
+ return text + part.resourceId;
+ }
+ return text + part.text;
+ }, "");
+ const {cmd, args} = getCommand(commandText);
+ return [cmd, args, commandText];
+ }
+
+ async _runSlashCommand(cmd, args, roomId) {
+ const result = cmd.run(roomId, args);
+ let messageContent;
+ let error = result.error;
+ if (result.promise) {
+ try {
+ if (cmd.category === CommandCategories.messages) {
+ messageContent = await result.promise;
+ } else {
+ await result.promise;
+ }
+ } catch (err) {
+ error = err;
+ }
+ }
+ if (error) {
+ console.error("Command failure: %s", error);
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ // assume the error is a server error when the command is async
+ const isServerError = !!result.promise;
+ const title = isServerError ? _td("Server error") : _td("Command error");
+
+ let errText;
+ if (typeof error === 'string') {
+ errText = error;
+ } else if (error.message) {
+ errText = error.message;
+ } else {
+ errText = _t("Server unavailable, overloaded, or something else went wrong.");
+ }
+
+ Modal.createTrackedDialog(title, '', ErrorDialog, {
+ title: _t(title),
+ description: errText,
+ });
+ } else {
+ console.log("Command success.");
+ if (messageContent) return messageContent;
+ }
+ }
+
+ _sendEdit = async () => {
const startTime = CountlyAnalytics.getTimestamp();
const editedEvent = this.props.editState.getEvent();
const editContent = createEditContent(this.model, editedEvent);
const newContent = editContent["m.new_content"];
+ let shouldSend = true;
// If content is modified then send an updated event into the room
if (this._isContentModified(newContent)) {
const roomId = editedEvent.getRoomId();
- this._cancelPreviousPendingEdit();
- const prom = this.context.sendMessage(roomId, editContent);
- dis.dispatch({action: "message_sent"});
- CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
+ if (!containsEmote(this.model) && this._isSlashCommand()) {
+ const [cmd, args, commandText] = this._getSlashCommand();
+ if (cmd) {
+ if (cmd.category === CommandCategories.messages) {
+ editContent["m.new_content"] = await this._runSlashCommand(cmd, args, roomId);
+ } else {
+ this._runSlashCommand(cmd, args, roomId);
+ shouldSend = false;
+ }
+ } else {
+ // ask the user if their unknown command should be sent as a message
+ const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
+ const {finished} = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, {
+ title: _t("Unknown Command"),
+ description:
+
+ { _t("Unrecognised command: %(commandText)s", {commandText}) }
+
+
+ { _t("You can use /help
to list available commands. " +
+ "Did you mean to send this as a message?", {}, {
+ code: t => { t }
,
+ }) }
+
+
+ { _t("Hint: Begin your message with //
to start it with a slash.", {}, {
+ code: t => { t }
,
+ }) }
+
+
,
+ button: _t('Send as message'),
+ });
+ const [sendAnyway] = await finished;
+ // if !sendAnyway bail to let the user edit the composer and try again
+ if (!sendAnyway) return;
+ }
+ }
+ if (shouldSend) {
+ this._cancelPreviousPendingEdit();
+ const prom = this.context.sendMessage(roomId, editContent);
+ dis.dispatch({action: "message_sent"});
+ CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
+ }
}
// close the event editing and focus composer
@@ -240,7 +351,7 @@ export default class EditMessageComposer extends React.Component {
_createEditorModel() {
const {editState} = this.props;
const room = this._getRoom();
- const partCreator = new PartCreator(room, this.context);
+ const partCreator = new CommandPartCreator(room, this.context);
let parts;
if (editState.hasEditorState()) {
// if restoring state from a previous editor,
diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx
index 36ab423885..411b0f9b5e 100644
--- a/src/components/views/spaces/SpacePanel.tsx
+++ b/src/components/views/spaces/SpacePanel.tsx
@@ -26,13 +26,11 @@ import {SpaceItem} from "./SpaceTreeLevel";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import {useEventEmitter} from "../../../hooks/useEventEmitter";
import SpaceStore, {
- HOME_SPACE,
UPDATE_INVITED_SPACES,
UPDATE_SELECTED_SPACE,
UPDATE_TOP_LEVEL_SPACES,
} from "../../../stores/SpaceStore";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
-import {SpaceNotificationState} from "../../../stores/notifications/SpaceNotificationState";
import NotificationBadge from "../rooms/NotificationBadge";
import {
RovingAccessibleButton,
@@ -40,13 +38,15 @@ import {
RovingTabIndexProvider,
} from "../../../accessibility/RovingTabIndex";
import {Key} from "../../../Keyboard";
+import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
+import {NotificationState} from "../../../stores/notifications/NotificationState";
interface IButtonProps {
space?: Room;
className?: string;
selected?: boolean;
tooltip?: string;
- notificationState?: SpaceNotificationState;
+ notificationState?: NotificationState;
isNarrow?: boolean;
onClick(): void;
}
@@ -212,8 +212,8 @@ const SpacePanel = () => {
className="mx_SpaceButton_home"
onClick={() => SpaceStore.instance.setActiveSpace(null)}
selected={!activeSpace}
- tooltip={_t("Home")}
- notificationState={SpaceStore.instance.getNotificationState(HOME_SPACE)}
+ tooltip={_t("All rooms")}
+ notificationState={RoomNotificationStateStore.instance.globalState}
isNarrow={isPanelCollapsed}
/>
{ invites.map(s => /help to list available commands. Did you mean to send this as a message?": "You can use /help
to list available commands. Did you mean to send this as a message?",
+ "Hint: Begin your message with //
to start it with a slash.": "Hint: Begin your message with //
to start it with a slash.",
+ "Send as message": "Send as message",
"Edit message": "Edit message",
"Mod": "Mod",
"This event could not be displayed": "This event could not be displayed",
@@ -1632,13 +1639,6 @@
"This Room": "This Room",
"All Rooms": "All Rooms",
"Search…": "Search…",
- "Server error": "Server error",
- "Server unavailable, overloaded, or something else went wrong.": "Server unavailable, overloaded, or something else went wrong.",
- "Unknown Command": "Unknown Command",
- "Unrecognised command: %(commandText)s": "Unrecognised command: %(commandText)s",
- "You can use /help
to list available commands. Did you mean to send this as a message?": "You can use /help
to list available commands. Did you mean to send this as a message?",
- "Hint: Begin your message with //
to start it with a slash.": "Hint: Begin your message with //
to start it with a slash.",
- "Send as message": "Send as message",
"Failed to connect to integration manager": "Failed to connect to integration manager",
"You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
"Add some now": "Add some now",
@@ -2017,10 +2017,10 @@
"Continue with %(provider)s": "Continue with %(provider)s",
"Sign in with single sign-on": "Sign in with single sign-on",
"And %(count)s more...|other": "And %(count)s more...",
+ "Home": "Home",
"Enter a server name": "Enter a server name",
"Looks good": "Looks good",
"Can't find this server or its room list": "Can't find this server or its room list",
- "All rooms": "All rooms",
"Your server": "Your server",
"Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s",
"Remove server": "Remove server",
diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx
index 4423891c61..b1b8199f93 100644
--- a/src/stores/SpaceStore.tsx
+++ b/src/stores/SpaceStore.tsx
@@ -31,28 +31,23 @@ import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateS
import {DefaultTagID} from "./room-list/models";
import {EnhancedMap, mapDiff} from "../utils/maps";
import {setHasDiff} from "../utils/sets";
-import {objectDiff} from "../utils/objects";
-import {arrayHasDiff} from "../utils/arrays";
import {ISpaceSummaryEvent, ISpaceSummaryRoom} from "../components/structures/SpaceRoomDirectory";
import RoomViewStore from "./RoomViewStore";
-type SpaceKey = string | symbol;
-
interface IState {}
const ACTIVE_SPACE_LS_KEY = "mx_active_space";
-export const HOME_SPACE = Symbol("home-space");
export const SUGGESTED_ROOMS = Symbol("suggested-rooms");
export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces");
export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
-// Space Room ID/HOME_SPACE will be emitted when a Space's children change
+// Space Room ID will be emitted when a Space's children change
const MAX_SUGGESTED_ROOMS = 20;
-const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "home_space"}`;
+const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "ALL_ROOMS"}`;
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms]
return arr.reduce((result, room: Room) => {
@@ -86,15 +81,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
// The spaces representing the roots of the various tree-like hierarchies
private rootSpaces: Room[] = [];
- // The list of rooms not present in any currently joined spaces
- private orphanedRooms = new Set();
// Map from room ID to set of spaces which list it as a child
private parentMap = new EnhancedMap>();
- // Map from space key to SpaceNotificationState instance representing that space
- private notificationStateMap = new Map();
+ // Map from spaceId to SpaceNotificationState instance representing that space
+ private notificationStateMap = new Map();
// Map from space key to Set of room IDs that should be shown as part of that space's filter
- private spaceFilteredRooms = new Map>();
- // The space currently selected in the Space Panel - if null then `Home` is selected
+ private spaceFilteredRooms = new Map>();
+ // The space currently selected in the Space Panel - if null then All Rooms is selected
private _activeSpace?: Room = null;
private _suggestedRooms: ISpaceSummaryRoom[] = [];
private _invitedSpaces = new Set();
@@ -244,7 +237,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
}
public getSpaceFilteredRoomIds = (space: Room | null): Set => {
- return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set();
+ if (!space) {
+ return new Set(this.matrixClient.getVisibleRooms().map(r => r.roomId));
+ }
+ return this.spaceFilteredRooms.get(space.roomId) || new Set();
};
private rebuild = throttle(() => {
@@ -275,7 +271,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
});
});
- const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren));
+ const [rootSpaces] = partitionSpacesAndRooms(Array.from(unseenChildren));
// somewhat algorithm to handle full-cycles
const detachedNodes = new Set(spaces);
@@ -316,7 +312,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
// rootSpaces.push(space);
// });
- this.orphanedRooms = new Set(orphanedRooms);
this.rootSpaces = rootSpaces;
this.parentMap = backrefs;
@@ -337,25 +332,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
this.rebuild();
}
- private showInHomeSpace = (room: Room) => {
- if (room.isSpaceRoom()) return false;
- return !this.parentMap.get(room.roomId)?.size // put all orphaned rooms in the Home Space
- || DMRoomMap.shared().getUserIdForRoomId(room.roomId) // put all DMs in the Home Space
- || RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite) // show all favourites
- };
-
- // Update a given room due to its tag changing (e.g DM-ness or Fav-ness)
- // This can only change whether it shows up in the HOME_SPACE or not
- private onRoomUpdate = (room: Room) => {
- if (this.showInHomeSpace(room)) {
- this.spaceFilteredRooms.get(HOME_SPACE)?.add(room.roomId);
- this.emit(HOME_SPACE);
- } else if (!this.orphanedRooms.has(room.roomId)) {
- this.spaceFilteredRooms.get(HOME_SPACE)?.delete(room.roomId);
- this.emit(HOME_SPACE);
- }
- };
-
private onSpaceMembersChange = (ev: MatrixEvent) => {
// skip this update if we do not have a DM with this user
if (DMRoomMap.shared().getDMRoomsForUserId(ev.getStateKey()).length < 1) return;
@@ -369,16 +345,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
const oldFilteredRooms = this.spaceFilteredRooms;
this.spaceFilteredRooms = new Map();
- // put all room invites in the Home Space
- const invites = visibleRooms.filter(r => !r.isSpaceRoom() && r.getMyMembership() === "invite");
- this.spaceFilteredRooms.set(HOME_SPACE, new Set(invites.map(room => room.roomId)));
-
- visibleRooms.forEach(room => {
- if (this.showInHomeSpace(room)) {
- this.spaceFilteredRooms.get(HOME_SPACE).add(room.roomId);
- }
- });
-
this.rootSpaces.forEach(s => {
// traverse each space tree in DFS to build up the supersets as you go up,
// reusing results from like subtrees.
@@ -425,13 +391,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
// Update NotificationStates
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
if (roomIds.has(room.roomId)) {
- // Don't aggregate notifications for DMs except in the Home Space
- if (s !== HOME_SPACE) {
- return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
- || RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
- }
-
- return true;
+ return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
+ || RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
}
return false;
@@ -513,8 +474,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
// TODO confirm this after implementing parenting behaviour
if (room.isSpaceRoom()) {
this.onSpaceUpdate();
- } else {
- this.onRoomUpdate(room);
}
this.emit(room.roomId);
break;
@@ -527,38 +486,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
}
};
- private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => {
- if (ev.getType() === EventType.Tag && !room.isSpaceRoom()) {
- // If the room was in favourites and now isn't or the opposite then update its position in the trees
- const oldTags = lastEvent?.getContent()?.tags || {};
- const newTags = ev.getContent()?.tags || {};
- if (!!oldTags[DefaultTagID.Favourite] !== !!newTags[DefaultTagID.Favourite]) {
- this.onRoomUpdate(room);
- }
- }
- }
-
- private onAccountData = (ev: MatrixEvent, lastEvent: MatrixEvent) => {
- if (ev.getType() === EventType.Direct) {
- const lastContent = lastEvent.getContent();
- const content = ev.getContent();
-
- const diff = objectDiff>(lastContent, content);
- // filter out keys which changed by reference only by checking whether the sets differ
- const changed = diff.changed.filter(k => arrayHasDiff(lastContent[k], content[k]));
- // DM tag changes, refresh relevant rooms
- new Set([...diff.added, ...diff.removed, ...changed]).forEach(roomId => {
- const room = this.matrixClient?.getRoom(roomId);
- if (room) {
- this.onRoomUpdate(room);
- }
- });
- }
- };
-
protected async reset() {
this.rootSpaces = [];
- this.orphanedRooms = new Set();
this.parentMap = new EnhancedMap();
this.notificationStateMap = new Map();
this.spaceFilteredRooms = new Map();
@@ -573,8 +502,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
this.matrixClient.removeListener("Room", this.onRoom);
this.matrixClient.removeListener("Room.myMembership", this.onRoom);
this.matrixClient.removeListener("RoomState.events", this.onRoomState);
- this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData);
- this.matrixClient.removeListener("accountData", this.onAccountData);
}
await this.reset();
}
@@ -584,8 +511,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
this.matrixClient.on("Room", this.onRoom);
this.matrixClient.on("Room.myMembership", this.onRoom);
this.matrixClient.on("RoomState.events", this.onRoomState);
- this.matrixClient.on("Room.accountData", this.onRoomAccountData);
- this.matrixClient.on("accountData", this.onAccountData);
await this.onSpaceUpdate(); // trigger an initial update
@@ -610,7 +535,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
// Don't context switch when navigating to the space room
// as it will cause you to end up in the wrong room
this.setActiveSpace(room, false);
- } else if (!this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
+ } else if (this.activeSpace && !this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
this.switchToRelatedSpace(roomId);
}
@@ -628,7 +553,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
}
}
- public getNotificationState(key: SpaceKey): SpaceNotificationState {
+ public getNotificationState(key: string): SpaceNotificationState {
if (this.notificationStateMap.has(key)) {
return this.notificationStateMap.get(key);
}
diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts
index 58eb6ed317..a23401e4c9 100644
--- a/src/stores/room-list/RoomListStore.ts
+++ b/src/stores/room-list/RoomListStore.ts
@@ -680,7 +680,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
promise = this.recalculatePrefiltering();
} else {
this.filterConditions.push(filter);
- // Runtime filters with spaces disable prefiltering for the search all spaces effect
+ // Runtime filters with spaces disable prefiltering for the search all spaces feature
if (SettingsStore.getValue("feature_spaces")) {
// this has to be awaited so that `setKnownRooms` is called in time for the `addFilterCondition` below
// this way the runtime filters are only evaluated on one dataset and not both.
@@ -712,10 +712,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
if (this.algorithm) {
this.algorithm.removeFilterCondition(filter);
- // Runtime filters with spaces disable prefiltering for the search all spaces effect
- if (SettingsStore.getValue("feature_spaces")) {
- promise = this.recalculatePrefiltering();
- }
+ }
+ // Runtime filters with spaces disable prefiltering for the search all spaces feature
+ if (SettingsStore.getValue("feature_spaces")) {
+ promise = this.recalculatePrefiltering();
}
}
idx = this.prefilterConditions.indexOf(filter);
diff --git a/src/stores/room-list/SpaceWatcher.ts b/src/stores/room-list/SpaceWatcher.ts
index 13e1d83901..0b1b78bc75 100644
--- a/src/stores/room-list/SpaceWatcher.ts
+++ b/src/stores/room-list/SpaceWatcher.ts
@@ -24,26 +24,34 @@ import SpaceStore, { UPDATE_SELECTED_SPACE } from "../SpaceStore";
* Watches for changes in spaces to manage the filter on the provided RoomListStore
*/
export class SpaceWatcher {
- private filter = new SpaceFilterCondition();
+ private filter: SpaceFilterCondition;
private activeSpace: Room = SpaceStore.instance.activeSpace;
constructor(private store: RoomListStoreClass) {
- this.updateFilter(); // get the filter into a consistent state
- store.addFilter(this.filter);
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated);
}
- private onSelectedSpaceUpdated = (activeSpace: Room) => {
+ private onSelectedSpaceUpdated = (activeSpace?: Room) => {
this.activeSpace = activeSpace;
- this.updateFilter();
+
+ if (this.filter) {
+ if (activeSpace) {
+ this.updateFilter();
+ } else {
+ this.store.removeFilter(this.filter);
+ this.filter = null;
+ }
+ } else if (activeSpace) {
+ this.filter = new SpaceFilterCondition();
+ this.updateFilter();
+ this.store.addFilter(this.filter);
+ }
};
private updateFilter = () => {
- if (this.activeSpace) {
- SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
- this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
- });
- }
+ SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
+ this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
+ });
this.filter.updateSpace(this.activeSpace);
};
}
diff --git a/src/stores/room-list/filters/SpaceFilterCondition.ts b/src/stores/room-list/filters/SpaceFilterCondition.ts
index 43bdcb3879..6a06bee0d8 100644
--- a/src/stores/room-list/filters/SpaceFilterCondition.ts
+++ b/src/stores/room-list/filters/SpaceFilterCondition.ts
@@ -19,7 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
import { IDestroyable } from "../../../utils/IDestroyable";
-import SpaceStore, {HOME_SPACE} from "../../SpaceStore";
+import SpaceStore from "../../SpaceStore";
import { setHasDiff } from "../../../utils/sets";
/**
@@ -55,10 +55,12 @@ export class SpaceFilterCondition extends EventEmitter implements IFilterConditi
}
};
- private getSpaceEventKey = (space: Room | null) => space ? space.roomId : HOME_SPACE;
+ private getSpaceEventKey = (space: Room) => space.roomId;
public updateSpace(space: Room) {
- SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
+ if (this.space) {
+ SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
+ }
SpaceStore.instance.on(this.getSpaceEventKey(this.space = space), this.onStoreUpdate);
this.onStoreUpdate(); // initial update from the change to the space
}
diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js
index 7347ff2658..dc70e3f7f6 100644
--- a/test/components/structures/MessagePanel-test.js
+++ b/test/components/structures/MessagePanel-test.js
@@ -77,7 +77,7 @@ describe('MessagePanel', function() {
DMRoomMap.makeShared();
});
- afterEach(function() {
+ afterEach(function () {
clock.uninstall();
});
@@ -88,7 +88,21 @@ describe('MessagePanel', function() {
events.push(test_utils.mkMessage(
{
event: true, room: "!room:id", user: "@user:id",
- ts: ts0 + i*1000,
+ ts: ts0 + i * 1000,
+ }));
+ }
+ return events;
+ }
+
+ // Just to avoid breaking Dateseparator tests that might run at 00hrs
+ function mkOneDayEvents() {
+ const events = [];
+ const ts0 = Date.parse('09 May 2004 00:12:00 GMT');
+ for (let i = 0; i < 10; i++) {
+ events.push(test_utils.mkMessage(
+ {
+ event: true, room: "!room:id", user: "@user:id",
+ ts: ts0 + i * 1000,
}));
}
return events;
@@ -104,7 +118,7 @@ describe('MessagePanel', function() {
let i = 0;
events.push(test_utils.mkMessage({
event: true, room: "!room:id", user: "@user:id",
- ts: ts0 + ++i*1000,
+ ts: ts0 + ++i * 1000,
}));
for (i = 0; i < 10; i++) {
@@ -151,7 +165,7 @@ describe('MessagePanel', function() {
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
- ts: ts0 + i*1000,
+ ts: ts0 + i * 1000,
mship: 'join',
prevMship: 'join',
name: 'A user',
@@ -250,7 +264,6 @@ describe('MessagePanel', function() {
}),
];
}
-
function isReadMarkerVisible(rmContainer) {
return rmContainer && rmContainer.children.length > 0;
}
@@ -437,4 +450,17 @@ describe('MessagePanel', function() {
// read marker should be hidden given props and at the last event
expect(isReadMarkerVisible(rm)).toBeFalsy();
});
+
+ it('should render Date separators for the events', function () {
+ const events = mkOneDayEvents();
+ const res = mount(
+ ,
+ );
+ const Dates = res.find(sdk.getComponent('messages.DateSeparator'));
+
+ expect(Dates.length).toEqual(1);
+ });
});
diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts
index aef788647d..20c48c29db 100644
--- a/test/stores/SpaceStore-test.ts
+++ b/test/stores/SpaceStore-test.ts
@@ -101,6 +101,7 @@ const invite1 = "!invite1:server";
const invite2 = "!invite2:server";
const room1 = "!room1:server";
const room2 = "!room2:server";
+const room3 = "!room3:server";
const space1 = "!space1:server";
const space2 = "!space2:server";
const space3 = "!space3:server";
@@ -361,8 +362,8 @@ describe("SpaceStore", () => {
expect(store.getSpaceFilteredRoomIds(null).has(invite2)).toBeTruthy();
});
- it("home space does not contain rooms/low priority from rooms within spaces", () => {
- expect(store.getSpaceFilteredRoomIds(null).has(room1)).toBeFalsy();
+ it("home space does contain rooms/low priority even if they are also shown in a space", () => {
+ expect(store.getSpaceFilteredRoomIds(null).has(room1)).toBeTruthy();
});
it("space contains child rooms", () => {
@@ -614,8 +615,8 @@ describe("SpaceStore", () => {
describe("space auto switching tests", () => {
beforeEach(async () => {
- [room1, room2, orphan1].forEach(mkRoom);
- mkSpace(space1, [room1, room2]);
+ [room1, room2, room3, orphan1].forEach(mkRoom);
+ mkSpace(space1, [room1, room2, room3]);
mkSpace(space2, [room1, room2]);
client.getRoom(room2).currentState.getStateEvents.mockImplementation(mockStateEventImplementation([
@@ -641,15 +642,15 @@ describe("SpaceStore", () => {
it("switch to canonical parent space for room", async () => {
viewRoom(room1);
- await store.setActiveSpace(null, false);
+ await store.setActiveSpace(client.getRoom(space2), false);
viewRoom(room2);
expect(store.activeSpace).toBe(client.getRoom(space2));
});
it("switch to first containing space for room", async () => {
viewRoom(room2);
- await store.setActiveSpace(null, false);
- viewRoom(room1);
+ await store.setActiveSpace(client.getRoom(space2), false);
+ viewRoom(room3);
expect(store.activeSpace).toBe(client.getRoom(space1));
});
@@ -659,6 +660,13 @@ describe("SpaceStore", () => {
viewRoom(orphan1);
expect(store.activeSpace).toBeNull();
});
+
+ it("when switching rooms in the all rooms home space don't switch to related space", async () => {
+ viewRoom(room2);
+ await store.setActiveSpace(null, false);
+ viewRoom(room1);
+ expect(store.activeSpace).toBeNull();
+ });
});
describe("traverseSpace", () => {
diff --git a/yarn.lock b/yarn.lock
index 8b4ac35d6a..0d9b2bdd3f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4226,9 +4226,9 @@ hoist-non-react-statics@^3.3.0:
react-is "^16.7.0"
hosted-git-info@^2.1.4:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
- integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
hosted-git-info@^3.0.6:
version "3.0.7"
@@ -5677,8 +5677,8 @@ mathml-tag-names@^2.1.3:
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
- version "10.0.0"
- resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c8f69c0b7937b9064938c134d708c4d064b71315"
+ version "10.1.0"
+ resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/2d73805ca3d8c5a140fe05e574f826696de1656a"
dependencies:
"@babel/runtime" "^7.12.5"
another-json "^0.2.0"
@@ -6307,6 +6307,11 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
+parse-srcset@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
+ integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=
+
parse5-htmlparser2-tree-adapter@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
@@ -7248,17 +7253,18 @@ sane@^4.0.3:
minimist "^1.1.1"
walker "~1.0.5"
-"sanitize-html@github:apostrophecms/sanitize-html#3c7f93f2058f696f5359e3e58d464161647226db":
- version "2.0.0-rc.3"
- resolved "https://codeload.github.com/apostrophecms/sanitize-html/tar.gz/3c7f93f2058f696f5359e3e58d464161647226db"
+sanitize-html@^2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.3.3.tgz#3db382c9a621cce4c46d90f10c64f1e9da9e8353"
+ integrity sha512-DCFXPt7Di0c6JUnlT90eIgrjs6TsJl/8HYU3KLdmrVclFN4O0heTcVbJiMa23OKVr6aR051XYtsgd8EWwEBwUA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
- htmlparser2 "^4.1.0"
+ htmlparser2 "^6.0.0"
is-plain-object "^5.0.0"
klona "^2.0.3"
+ parse-srcset "^1.0.2"
postcss "^8.0.2"
- srcset "^3.0.0"
saxes@^5.0.0:
version "5.0.1"
@@ -7515,11 +7521,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-srcset@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/srcset/-/srcset-3.0.0.tgz#8afd8b971362dfc129ae9c1a99b3897301ce6441"
- integrity sha512-D59vF08Qzu/C4GAOXVgMTLfgryt5fyWo93FZyhEWANo0PokFz/iWdDe13mX3O5TRf6l8vMTqckAfR4zPiaH0yQ==
-
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"