Merge remote-tracking branch 'upstream/develop' into feature/muting

pull/21833/head
Šimon Brandner 2021-07-29 09:06:24 +02:00
commit cf973cdb95
No known key found for this signature in database
GPG Key ID: 55C211A1226CB17D
20 changed files with 250 additions and 135 deletions

View File

@ -104,8 +104,8 @@ a:visited {
input[type=text],
input[type=search],
input[type=password] {
font-family: inherit;
padding: 9px;
font-family: $font-family;
font-size: $font-14px;
font-weight: 600;
min-width: 0;
@ -146,7 +146,6 @@ input[type=text], input[type=password], textarea {
/* Required by Firefox */
textarea {
font-family: $font-family;
color: $primary-fg-color;
}

View File

@ -29,7 +29,6 @@ limitations under the License.
.mx_AddressPickerDialog_input:focus {
height: 26px;
font-size: $font-14px;
font-family: $font-family;
padding-left: 12px;
padding-right: 12px;
margin: 0 !important;

View File

@ -34,7 +34,6 @@ limitations under the License.
}
.mx_ConfirmUserActionDialog_reasonField {
font-family: $font-family;
font-size: $font-14px;
color: $primary-fg-color;
background-color: $primary-bg-color;

View File

@ -55,22 +55,6 @@ limitations under the License.
padding-right: 24px;
}
.mx_DevTools_inputCell {
display: table-cell;
width: 240px;
}
.mx_DevTools_inputCell input {
display: inline-block;
border: 0;
border-bottom: 1px solid $input-underline-color;
padding: 0;
width: 240px;
color: $input-fg-color;
font-family: $font-family;
font-size: $font-16px;
}
.mx_DevTools_textarea {
font-size: $font-12px;
max-width: 684px;
@ -139,7 +123,6 @@ limitations under the License.
+ .mx_DevTools_tgl-btn {
padding: 2px;
transition: all .2s ease;
font-family: sans-serif;
perspective: 100px;
&::after,
&::before {

View File

@ -39,7 +39,6 @@ limitations under the License.
.mx_Field select,
.mx_Field textarea {
font-weight: normal;
font-family: $font-family;
font-size: $font-14px;
border: none;
// Even without a border here, we still need this avoid overlapping the rounded

View File

@ -132,15 +132,6 @@ $hover-select-border: 4px;
}
}
&.mx_EventTile_info .mx_EventTile_line,
& ~ .mx_EventListSummary > :not(.mx_EventTile) .mx_EventTile_avatar ~ .mx_EventTile_line {
padding-left: calc($left-gutter + 18px);
}
& ~ .mx_EventListSummary .mx_EventTile_line {
padding-left: calc($left-gutter);
}
&.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line {
padding-left: calc($left-gutter + 18px - $hover-select-border);
}
@ -276,10 +267,19 @@ $hover-select-border: 4px;
.mx_ReactionsRow {
margin: 0;
padding: 6px 60px;
padding: 4px 64px;
}
}
.mx_EventTile:not([data-layout=bubble]).mx_EventTile_info .mx_EventTile_line,
.mx_EventListSummary:not([data-layout=bubble]) > :not(.mx_EventTile) .mx_EventTile_avatar ~ .mx_EventTile_line {
padding-left: calc($left-gutter + 18px);
}
.mx_EventListSummary:not([data-layout=bubble]) .mx_EventTile_line {
padding-left: calc($left-gutter);
}
/* all the overflow-y: hidden; are to trap Zalgos -
but they introduce an implicit overflow-x: auto.
so make that explicitly hidden too to avoid random

View File

@ -165,8 +165,6 @@ limitations under the License.
font-size: $font-14px;
max-height: 120px;
overflow: auto;
/* needed for FF */
font-family: $font-family;
}
/* hack for FF as vertical alignment of custom placeholder text is broken */

View File

@ -36,7 +36,6 @@ limitations under the License.
.mx_SettingsTab_subheading {
font-size: $font-16px;
display: block;
font-family: $font-family;
font-weight: 600;
color: $primary-fg-color;
margin-bottom: 10px;

View File

@ -279,7 +279,7 @@ limitations under the License.
max-width: 240px;
}
.mx_CallView_header_phoneIcon {
.mx_CallView_header_callTypeIcon {
display: inline-block;
margin-right: 6px;
height: 16px;
@ -293,12 +293,19 @@ limitations under the License.
height: 16px;
width: 16px;
background-color: $warning-color;
background-color: $secondary-fg-color;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
}
&.mx_CallView_header_callTypeIcon_voice::before {
mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
}
&.mx_CallView_header_callTypeIcon_video::before {
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
}
}
.mx_CallView_callControls {
@ -306,7 +313,6 @@ limitations under the License.
display: flex;
justify-content: center;
bottom: 5px;
width: 100%;
opacity: 1;
transition: opacity 0.5s;
z-index: 200; // To be above _all_ feeds

View File

@ -250,7 +250,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Public) {
} else if (this.state.joinRule === JoinRule.Public && this.props.parentSpace) {
publicPrivateLabel = <p>
{ _t(
"Anyone will be able to find and join this room, not just members of <SpaceName/>.", {}, {
@ -260,6 +260,12 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Public) {
publicPrivateLabel = <p>
{ _t("Anyone will be able to find and join this room.") }
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Invite) {
publicPrivateLabel = <p>
{ _t(

View File

@ -67,15 +67,21 @@ export default class ReplyTile extends React.PureComponent<IProps> {
};
private onClick = (e: React.MouseEvent): void => {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Riot when clicked.
e.preventDefault();
dis.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
const clickTarget = e.target as HTMLElement;
// Following a link within a reply should not dispatch the `view_room` action
// so that the browser can direct the user to the correct location
// The exception being the link wrapping the reply
if (clickTarget.tagName.toLowerCase() !== "a" || clickTarget.closest("a") === null) {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Riot when clicked.
e.preventDefault();
dis.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
}
};
render() {

View File

@ -67,6 +67,7 @@ interface IState {
screensharing: boolean;
callState: CallState;
controlsVisible: boolean;
hoveringControls: boolean;
showMoreMenu: boolean;
showDialpad: boolean;
primaryFeed: CallFeed;
@ -102,7 +103,7 @@ function exitFullscreen() {
if (exitMethod) exitMethod.call(document);
}
const CONTROLS_HIDE_DELAY = 1000;
const CONTROLS_HIDE_DELAY = 2000;
// Height of the header duplicated from CSS because we need to subtract it from our max
// height to get the max height of the video
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)
@ -128,6 +129,7 @@ export default class CallView extends React.Component<IProps, IState> {
screensharing: this.props.call.isScreensharing(),
callState: this.props.call.state,
controlsVisible: true,
hoveringControls: false,
showMoreMenu: false,
showDialpad: false,
primaryFeed: primary,
@ -244,6 +246,7 @@ export default class CallView extends React.Component<IProps, IState> {
};
private onControlsHideTimer = () => {
if (this.state.hoveringControls || this.state.showDialpad || this.state.showMoreMenu) return;
this.controlsHideTimer = null;
this.setState({
controlsVisible: false,
@ -293,24 +296,10 @@ export default class CallView extends React.Component<IProps, IState> {
private onDialpadClick = (): void => {
if (!this.state.showDialpad) {
if (this.controlsHideTimer) {
clearTimeout(this.controlsHideTimer);
this.controlsHideTimer = null;
}
this.setState({
showDialpad: true,
controlsVisible: true,
});
this.setState({ showDialpad: true });
this.showControls();
} else {
if (this.controlsHideTimer !== null) {
clearTimeout(this.controlsHideTimer);
}
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
this.setState({
showDialpad: false,
});
this.setState({ showDialpad: false });
}
};
@ -345,29 +334,16 @@ export default class CallView extends React.Component<IProps, IState> {
};
private onMoreClick = (): void => {
if (this.controlsHideTimer) {
clearTimeout(this.controlsHideTimer);
this.controlsHideTimer = null;
}
this.setState({
showMoreMenu: true,
controlsVisible: true,
});
this.setState({ showMoreMenu: true });
this.showControls();
};
private closeDialpad = (): void => {
this.setState({
showDialpad: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
this.setState({ showDialpad: false });
};
private closeContextMenu = (): void => {
this.setState({
showMoreMenu: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
this.setState({ showMoreMenu: false });
};
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
@ -403,6 +379,15 @@ export default class CallView extends React.Component<IProps, IState> {
}
};
private onCallControlsMouseEnter = (): void => {
this.setState({ hoveringControls: true });
this.showControls();
};
private onCallControlsMouseLeave = (): void => {
this.setState({ hoveringControls: false });
};
private onRoomAvatarClick = (): void => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
dis.dispatch({
@ -537,8 +522,6 @@ export default class CallView extends React.Component<IProps, IState> {
}
// The dial pad & 'more' button actions are only relevant in a connected call
// When not connected, we have to put something there to make the flexbox alignment correct
let dialpadButton;
let contextMenuButton;
if (this.state.callState === CallState.Connected) {
contextMenuButton = (
@ -549,6 +532,9 @@ export default class CallView extends React.Component<IProps, IState> {
isExpanded={this.state.showMoreMenu}
/>
);
}
let dialpadButton;
if (this.state.callState === CallState.Connected && this.props.call.opponentSupportsDTMF()) {
dialpadButton = (
<ContextMenuButton
className="mx_CallView_callControls_button mx_CallView_callControls_dialpad"
@ -560,7 +546,11 @@ export default class CallView extends React.Component<IProps, IState> {
}
return (
<div className={callControlsClasses}>
<div
className={callControlsClasses}
onMouseEnter={this.onCallControlsMouseEnter}
onMouseLeave={this.onCallControlsMouseLeave}
>
{ dialpadButton }
<AccessibleButton
className={micClasses}
@ -821,10 +811,15 @@ export default class CallView extends React.Component<IProps, IState> {
{ expandButton }
</div>;
const callTypeIconClassName = classNames("mx_CallView_header_callTypeIcon", {
"mx_CallView_header_callTypeIcon_voice": !isVideoCall,
"mx_CallView_header_callTypeIcon_video": isVideoCall,
});
let header: React.ReactNode;
if (!this.props.pipMode) {
header = <div className="mx_CallView_header">
<div className="mx_CallView_header_phoneIcon" />
<div className={callTypeIconClassName} />
<span className="mx_CallView_header_callType">{ callTypeText }</span>
{ headerControls }
</div>;

View File

@ -0,0 +1,53 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Populate this class with the details of your customisations when copying it.
import { ITemplateParams } from "matrix-widget-api";
/**
* Provides a partial set of the variables needed to render any widget. If
* variables are missing or not provided then they will be filled with the
* application-determined defaults.
*
* This will not be called until after isReady() resolves.
* @returns {Partial<Omit<ITemplateParams, "widgetRoomId">>} The variables.
*/
function provideVariables(): Partial<Omit<ITemplateParams, "widgetRoomId">> {
return {};
}
/**
* Resolves to whether or not the customisation point is ready for variables
* to be provided. This will block widgets being rendered.
* @returns {Promise<boolean>} Resolves when ready.
*/
async function isReady(): Promise<void> {
return; // default no waiting
}
// This interface summarises all available customisation points and also marks
// them all as optional. This allows customisers to only define and export the
// customisations they need while still maintaining type safety.
export interface IWidgetVariablesCustomisations {
provideVariables?: typeof provideVariables;
// If not provided, the app will assume that the customisation is always ready.
isReady?: typeof isReady;
}
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const WidgetVariableCustomisations: IWidgetVariablesCustomisations = {};

View File

@ -797,9 +797,6 @@
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.",
"Your feedback will help make spaces better. The more detail you can go into, the better.": "Your feedback will help make spaces better. The more detail you can go into, the better.",
"Show all rooms in Home": "Show all rooms in Home",
"Show people in spaces": "Show people in spaces",
"If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.": "If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.",
"Show notification badges for People in Spaces": "Show notification badges for People in Spaces",
"Show options to enable 'Do not disturb' mode": "Show options to enable 'Do not disturb' mode",
"Send and receive voice messages": "Send and receive voice messages",
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
@ -2200,6 +2197,7 @@
"Everyone in <SpaceName/> will be able to find and join this room.": "Everyone in <SpaceName/> will be able to find and join this room.",
"You can change this at any time from room settings.": "You can change this at any time from room settings.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Anyone will be able to find and join this room, not just members of <SpaceName/>.",
"Anyone will be able to find and join this room.": "Anyone will be able to find and join this room.",
"Only people invited will be able to find and join this room.": "Only people invited will be able to find and join this room.",
"You cant disable this later. Bridges & most bots wont work yet.": "You cant disable this later. Bridges & most bots wont work yet.",
"Your server requires encryption to be enabled in private rooms.": "Your server requires encryption to be enabled in private rooms.",

View File

@ -181,8 +181,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
feedbackLabel: "spaces-feedback",
extraSettings: [
"feature_spaces.all_rooms",
"feature_spaces.space_member_dms",
"feature_spaces.space_dm_badges",
],
},
},
@ -192,20 +190,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
default: true,
controller: new ReloadOnChangeController(),
},
"feature_spaces.space_member_dms": {
displayName: _td("Show people in spaces"),
description: _td("If disabled, you can still add Direct Messages to Personal Spaces. " +
"If enabled, you'll automatically see everyone who is a member of the Space."),
supportedLevels: LEVELS_FEATURE,
default: true,
controller: new ReloadOnChangeController(),
},
"feature_spaces.space_dm_badges": {
displayName: _td("Show notification badges for People in Spaces"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new ReloadOnChangeController(),
},
"feature_dnd": {
isFeature: true,
displayName: _td("Show options to enable 'Do not disturb' mode"),

View File

@ -72,8 +72,6 @@ const MAX_SUGGESTED_ROOMS = 20;
// All of these settings cause the page to reload and can be costly if read frequently, so read them here only
const spacesEnabled = SettingsStore.getValue("feature_spaces");
const spacesTweakAllRoomsEnabled = SettingsStore.getValue("feature_spaces.all_rooms");
const spacesTweakSpaceMemberDMsEnabled = SettingsStore.getValue("feature_spaces.space_member_dms");
const spacesTweakSpaceDMBadgesEnabled = SettingsStore.getValue("feature_spaces.space_dm_badges");
const homeSpaceKey = spacesTweakAllRoomsEnabled ? "ALL_ROOMS" : "HOME_SPACE";
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || homeSpaceKey}`;
@ -535,15 +533,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
const roomIds = new Set(childRooms.map(r => r.roomId));
const space = this.matrixClient?.getRoom(spaceId);
if (spacesTweakSpaceMemberDMsEnabled) {
// Add relevant DMs
space?.getMembers().forEach(member => {
if (member.membership !== "join" && member.membership !== "invite") return;
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
roomIds.add(roomId);
});
// Add relevant DMs
space?.getMembers().forEach(member => {
if (member.membership !== "join" && member.membership !== "invite") return;
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
roomIds.add(roomId);
});
}
});
const newPath = new Set(parentPath).add(spaceId);
childSpaces.forEach(childSpace => {
@ -568,14 +564,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
this.spaceFilteredRooms.forEach((roomIds, s) => {
// Update NotificationStates
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
if (roomIds.has(room.roomId)) {
if (s !== HOME_SPACE && spacesTweakSpaceDMBadgesEnabled) return true;
if (!roomIds.has(room.roomId)) return false;
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
return s === HOME_SPACE;
}
return false;
return true;
}));
});
}, 100, { trailing: true, leading: true });
@ -878,8 +873,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
export default class SpaceStore {
public static spacesEnabled = spacesEnabled;
public static spacesTweakAllRoomsEnabled = spacesTweakAllRoomsEnabled;
public static spacesTweakSpaceMemberDMsEnabled = spacesTweakSpaceMemberDMsEnabled;
public static spacesTweakSpaceDMBadgesEnabled = spacesTweakSpaceDMBadgesEnabled;
private static internalInstance = new SpaceStoreClass();

View File

@ -23,7 +23,7 @@ import { NOTIFICATION_STATE_UPDATE, NotificationState } from "./NotificationStat
import { FetchRoomFn } from "./ListNotificationState";
export class SpaceNotificationState extends NotificationState {
private rooms: Room[] = [];
public rooms: Room[] = []; // exposed only for tests
private states: { [spaceId: string]: RoomNotificationState } = {};
constructor(private spaceId: string | symbol, private getRoomFn: FetchRoomFn) {

View File

@ -54,6 +54,7 @@ import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { ELEMENT_CLIENT_ID } from "../../identifiers";
import { getUserLanguage } from "../../languageHandler";
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
// TODO: Destroy all of this code
@ -191,7 +192,8 @@ export class StopGapWidget extends EventEmitter {
}
private runUrlTemplate(opts = { asPopout: false }): string {
const templated = this.mockWidget.getCompleteUrl({
const fromCustomisation = WidgetVariableCustomisations?.provideVariables?.() ?? {};
const defaults: ITemplateParams = {
widgetRoomId: this.roomId,
currentUserId: MatrixClientPeg.get().getUserId(),
userDisplayName: OwnProfileStore.instance.displayName,
@ -199,7 +201,8 @@ export class StopGapWidget extends EventEmitter {
clientId: ELEMENT_CLIENT_ID,
clientTheme: SettingsStore.getValue("theme"),
clientLanguage: getUserLanguage(),
}, opts?.asPopout);
};
const templated = this.mockWidget.getCompleteUrl(Object.assign(defaults, fromCustomisation), opts?.asPopout);
const parsed = new URL(templated);
@ -363,6 +366,9 @@ export class StopGapWidget extends EventEmitter {
}
public async prepare(): Promise<void> {
// Ensure the variables are ready for us to be rendered before continuing
await (WidgetVariableCustomisations?.isReady?.() ?? Promise.resolve());
if (this.scalarToken) return;
const existingMessaging = WidgetMessagingStore.instance.getMessaging(this.mockWidget);
if (existingMessaging) this.messaging = existingMessaging;

View File

@ -19,5 +19,3 @@ limitations under the License.
localStorage.setItem("mx_labs_feature_feature_spaces", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.all_rooms", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.space_member_dms", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.space_dm_badges", "false");

View File

@ -17,6 +17,7 @@ limitations under the License.
import { EventEmitter } from "events";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import "./SpaceStore-setup"; // enable space lab
import "../skinned-sdk"; // Must be first for skinning to work
@ -53,18 +54,22 @@ const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.
const testUserId = "@test:user";
const getUserIdForRoomId = jest.fn();
const getDMRoomsForUserId = jest.fn();
// @ts-ignore
DMRoomMap.sharedInstance = { getUserIdForRoomId };
DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId };
const fav1 = "!fav1:server";
const fav2 = "!fav2:server";
const fav3 = "!fav3:server";
const dm1 = "!dm1:server";
const dm1Partner = "@dm1Partner:server";
const dm1Partner = new RoomMember(dm1, "@dm1Partner:server");
dm1Partner.membership = "join";
const dm2 = "!dm2:server";
const dm2Partner = "@dm2Partner:server";
const dm2Partner = new RoomMember(dm2, "@dm2Partner:server");
dm2Partner.membership = "join";
const dm3 = "!dm3:server";
const dm3Partner = "@dm3Partner:server";
const dm3Partner = new RoomMember(dm3, "@dm3Partner:server");
dm3Partner.membership = "join";
const orphan1 = "!orphan1:server";
const orphan2 = "!orphan2:server";
const invite1 = "!invite1:server";
@ -320,11 +325,40 @@ describe("SpaceStore", () => {
getUserIdForRoomId.mockImplementation(roomId => {
return {
[dm1]: dm1Partner,
[dm2]: dm2Partner,
[dm3]: dm3Partner,
[dm1]: dm1Partner.userId,
[dm2]: dm2Partner.userId,
[dm3]: dm3Partner.userId,
}[roomId];
});
getDMRoomsForUserId.mockImplementation(userId => {
switch (userId) {
case dm1Partner.userId:
return [dm1];
case dm2Partner.userId:
return [dm2];
case dm3Partner.userId:
return [dm3];
default:
return [];
}
});
// have dmPartner1 be in space1 with you
const mySpace1Member = new RoomMember(space1, testUserId);
mySpace1Member.membership = "join";
(rooms.find(r => r.roomId === space1).getMembers as jest.Mock).mockReturnValue([
mySpace1Member,
dm1Partner,
]);
// have dmPartner2 be in space2 with you
const mySpace2Member = new RoomMember(space2, testUserId);
mySpace2Member.membership = "join";
(rooms.find(r => r.roomId === space2).getMembers as jest.Mock).mockReturnValue([
mySpace2Member,
dm2Partner,
]);
// dmPartner3 is not in any common spaces with you
await run();
});
@ -375,6 +409,66 @@ describe("SpaceStore", () => {
const space = client.getRoom(space3);
expect(store.getSpaceFilteredRoomIds(space).has(invite2)).toBeTruthy();
});
it("spaces contain dms which you have with members of that space", () => {
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm1)).toBeTruthy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm1)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm1)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm2)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm2)).toBeTruthy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm2)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm3)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm3)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm3)).toBeFalsy();
});
it("dms are only added to Notification States for only the Home Space", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [dm1, dm2, dm3].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
[space1, space2, space3].forEach(s => {
[dm1, dm2, dm3].forEach(d => {
expect(store.getNotificationState(s).rooms.map(r => r.roomId).includes(d)).toBeFalsy();
});
});
});
it("orphan rooms are added to Notification States for only the Home Space", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [orphan1, orphan2].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
[space1, space2, space3].forEach(s => {
[orphan1, orphan2].forEach(d => {
expect(store.getNotificationState(s).rooms.map(r => r.roomId).includes(d)).toBeFalsy();
});
});
});
it("favourites are added to Notification States for all spaces containing the room inc Home", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [fav1, fav2, fav3].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav1)).toBeTruthy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav2)).toBeFalsy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav3)).toBeFalsy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav1)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav2)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav3)).toBeTruthy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav1)).toBeFalsy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav2)).toBeFalsy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav3)).toBeFalsy();
});
it("other rooms are added to Notification States for all spaces containing the room exc Home", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(room1)).toBeFalsy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(room1)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(room1)).toBeTruthy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(room1)).toBeFalsy();
});
});
});