Merge remote-tracking branch 'upstream/develop' into feature/muting
This commit is contained in:
commit
cf973cdb95
20 changed files with 250 additions and 135 deletions
|
@ -104,8 +104,8 @@ a:visited {
|
||||||
input[type=text],
|
input[type=text],
|
||||||
input[type=search],
|
input[type=search],
|
||||||
input[type=password] {
|
input[type=password] {
|
||||||
|
font-family: inherit;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
font-family: $font-family;
|
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
@ -146,7 +146,6 @@ input[type=text], input[type=password], textarea {
|
||||||
|
|
||||||
/* Required by Firefox */
|
/* Required by Firefox */
|
||||||
textarea {
|
textarea {
|
||||||
font-family: $font-family;
|
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ limitations under the License.
|
||||||
.mx_AddressPickerDialog_input:focus {
|
.mx_AddressPickerDialog_input:focus {
|
||||||
height: 26px;
|
height: 26px;
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
font-family: $font-family;
|
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
|
|
|
@ -34,7 +34,6 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ConfirmUserActionDialog_reasonField {
|
.mx_ConfirmUserActionDialog_reasonField {
|
||||||
font-family: $font-family;
|
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
||||||
|
|
|
@ -55,22 +55,6 @@ limitations under the License.
|
||||||
padding-right: 24px;
|
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 {
|
.mx_DevTools_textarea {
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
max-width: 684px;
|
max-width: 684px;
|
||||||
|
@ -139,7 +123,6 @@ limitations under the License.
|
||||||
+ .mx_DevTools_tgl-btn {
|
+ .mx_DevTools_tgl-btn {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
transition: all .2s ease;
|
transition: all .2s ease;
|
||||||
font-family: sans-serif;
|
|
||||||
perspective: 100px;
|
perspective: 100px;
|
||||||
&::after,
|
&::after,
|
||||||
&::before {
|
&::before {
|
||||||
|
|
|
@ -39,7 +39,6 @@ limitations under the License.
|
||||||
.mx_Field select,
|
.mx_Field select,
|
||||||
.mx_Field textarea {
|
.mx_Field textarea {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-family: $font-family;
|
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
border: none;
|
border: none;
|
||||||
// Even without a border here, we still need this avoid overlapping the rounded
|
// Even without a border here, we still need this avoid overlapping the rounded
|
||||||
|
|
|
@ -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 {
|
&.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line {
|
||||||
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
||||||
}
|
}
|
||||||
|
@ -276,10 +267,19 @@ $hover-select-border: 4px;
|
||||||
|
|
||||||
.mx_ReactionsRow {
|
.mx_ReactionsRow {
|
||||||
margin: 0;
|
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 -
|
/* all the overflow-y: hidden; are to trap Zalgos -
|
||||||
but they introduce an implicit overflow-x: auto.
|
but they introduce an implicit overflow-x: auto.
|
||||||
so make that explicitly hidden too to avoid random
|
so make that explicitly hidden too to avoid random
|
||||||
|
|
|
@ -165,8 +165,6 @@ limitations under the License.
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
max-height: 120px;
|
max-height: 120px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
/* needed for FF */
|
|
||||||
font-family: $font-family;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hack for FF as vertical alignment of custom placeholder text is broken */
|
/* hack for FF as vertical alignment of custom placeholder text is broken */
|
||||||
|
|
|
@ -36,7 +36,6 @@ limitations under the License.
|
||||||
.mx_SettingsTab_subheading {
|
.mx_SettingsTab_subheading {
|
||||||
font-size: $font-16px;
|
font-size: $font-16px;
|
||||||
display: block;
|
display: block;
|
||||||
font-family: $font-family;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
|
@ -279,7 +279,7 @@ limitations under the License.
|
||||||
max-width: 240px;
|
max-width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_CallView_header_phoneIcon {
|
.mx_CallView_header_callTypeIcon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
@ -293,12 +293,19 @@ limitations under the License.
|
||||||
|
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
background-color: $warning-color;
|
background-color: $secondary-fg-color;
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
mask-size: contain;
|
mask-size: contain;
|
||||||
mask-position: center;
|
mask-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_CallView_header_callTypeIcon_voice::before {
|
||||||
mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
|
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 {
|
.mx_CallView_callControls {
|
||||||
|
@ -306,7 +313,6 @@ limitations under the License.
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
width: 100%;
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 0.5s;
|
transition: opacity 0.5s;
|
||||||
z-index: 200; // To be above _all_ feeds
|
z-index: 200; // To be above _all_ feeds
|
||||||
|
|
|
@ -250,7 +250,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
{ _t("You can change this at any time from room settings.") }
|
{ _t("You can change this at any time from room settings.") }
|
||||||
</p>;
|
</p>;
|
||||||
} else if (this.state.joinRule === JoinRule.Public) {
|
} else if (this.state.joinRule === JoinRule.Public && this.props.parentSpace) {
|
||||||
publicPrivateLabel = <p>
|
publicPrivateLabel = <p>
|
||||||
{ _t(
|
{ _t(
|
||||||
"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/>.", {}, {
|
||||||
|
@ -260,6 +260,12 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
{ _t("You can change this at any time from room settings.") }
|
{ _t("You can change this at any time from room settings.") }
|
||||||
</p>;
|
</p>;
|
||||||
|
} else if (this.state.joinRule === JoinRule.Public) {
|
||||||
|
publicPrivateLabel = <p>
|
||||||
|
{ _t("Anyone will be able to find and join this room.") }
|
||||||
|
|
||||||
|
{ _t("You can change this at any time from room settings.") }
|
||||||
|
</p>;
|
||||||
} else if (this.state.joinRule === JoinRule.Invite) {
|
} else if (this.state.joinRule === JoinRule.Invite) {
|
||||||
publicPrivateLabel = <p>
|
publicPrivateLabel = <p>
|
||||||
{ _t(
|
{ _t(
|
||||||
|
|
|
@ -67,15 +67,21 @@ export default class ReplyTile extends React.PureComponent<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClick = (e: React.MouseEvent): void => {
|
private onClick = (e: React.MouseEvent): void => {
|
||||||
// This allows the permalink to be opened in a new tab/window or copied as
|
const clickTarget = e.target as HTMLElement;
|
||||||
// matrix.to, but also for it to enable routing within Riot when clicked.
|
// Following a link within a reply should not dispatch the `view_room` action
|
||||||
e.preventDefault();
|
// so that the browser can direct the user to the correct location
|
||||||
dis.dispatch({
|
// The exception being the link wrapping the reply
|
||||||
action: 'view_room',
|
if (clickTarget.tagName.toLowerCase() !== "a" || clickTarget.closest("a") === null) {
|
||||||
event_id: this.props.mxEvent.getId(),
|
// This allows the permalink to be opened in a new tab/window or copied as
|
||||||
highlighted: true,
|
// matrix.to, but also for it to enable routing within Riot when clicked.
|
||||||
room_id: this.props.mxEvent.getRoomId(),
|
e.preventDefault();
|
||||||
});
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
event_id: this.props.mxEvent.getId(),
|
||||||
|
highlighted: true,
|
||||||
|
room_id: this.props.mxEvent.getRoomId(),
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -67,6 +67,7 @@ interface IState {
|
||||||
screensharing: boolean;
|
screensharing: boolean;
|
||||||
callState: CallState;
|
callState: CallState;
|
||||||
controlsVisible: boolean;
|
controlsVisible: boolean;
|
||||||
|
hoveringControls: boolean;
|
||||||
showMoreMenu: boolean;
|
showMoreMenu: boolean;
|
||||||
showDialpad: boolean;
|
showDialpad: boolean;
|
||||||
primaryFeed: CallFeed;
|
primaryFeed: CallFeed;
|
||||||
|
@ -102,7 +103,7 @@ function exitFullscreen() {
|
||||||
if (exitMethod) exitMethod.call(document);
|
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 of the header duplicated from CSS because we need to subtract it from our max
|
||||||
// height to get the max height of the video
|
// height to get the max height of the video
|
||||||
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)
|
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(),
|
screensharing: this.props.call.isScreensharing(),
|
||||||
callState: this.props.call.state,
|
callState: this.props.call.state,
|
||||||
controlsVisible: true,
|
controlsVisible: true,
|
||||||
|
hoveringControls: false,
|
||||||
showMoreMenu: false,
|
showMoreMenu: false,
|
||||||
showDialpad: false,
|
showDialpad: false,
|
||||||
primaryFeed: primary,
|
primaryFeed: primary,
|
||||||
|
@ -244,6 +246,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onControlsHideTimer = () => {
|
private onControlsHideTimer = () => {
|
||||||
|
if (this.state.hoveringControls || this.state.showDialpad || this.state.showMoreMenu) return;
|
||||||
this.controlsHideTimer = null;
|
this.controlsHideTimer = null;
|
||||||
this.setState({
|
this.setState({
|
||||||
controlsVisible: false,
|
controlsVisible: false,
|
||||||
|
@ -293,24 +296,10 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private onDialpadClick = (): void => {
|
private onDialpadClick = (): void => {
|
||||||
if (!this.state.showDialpad) {
|
if (!this.state.showDialpad) {
|
||||||
if (this.controlsHideTimer) {
|
this.setState({ showDialpad: true });
|
||||||
clearTimeout(this.controlsHideTimer);
|
this.showControls();
|
||||||
this.controlsHideTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
showDialpad: true,
|
|
||||||
controlsVisible: true,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (this.controlsHideTimer !== null) {
|
this.setState({ showDialpad: false });
|
||||||
clearTimeout(this.controlsHideTimer);
|
|
||||||
}
|
|
||||||
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
showDialpad: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -345,29 +334,16 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onMoreClick = (): void => {
|
private onMoreClick = (): void => {
|
||||||
if (this.controlsHideTimer) {
|
this.setState({ showMoreMenu: true });
|
||||||
clearTimeout(this.controlsHideTimer);
|
this.showControls();
|
||||||
this.controlsHideTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
showMoreMenu: true,
|
|
||||||
controlsVisible: true,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private closeDialpad = (): void => {
|
private closeDialpad = (): void => {
|
||||||
this.setState({
|
this.setState({ showDialpad: false });
|
||||||
showDialpad: false,
|
|
||||||
});
|
|
||||||
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private closeContextMenu = (): void => {
|
private closeContextMenu = (): void => {
|
||||||
this.setState({
|
this.setState({ showMoreMenu: false });
|
||||||
showMoreMenu: false,
|
|
||||||
});
|
|
||||||
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
|
// 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 => {
|
private onRoomAvatarClick = (): void => {
|
||||||
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
|
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
|
||||||
dis.dispatch({
|
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
|
// 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;
|
let contextMenuButton;
|
||||||
if (this.state.callState === CallState.Connected) {
|
if (this.state.callState === CallState.Connected) {
|
||||||
contextMenuButton = (
|
contextMenuButton = (
|
||||||
|
@ -549,6 +532,9 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
isExpanded={this.state.showMoreMenu}
|
isExpanded={this.state.showMoreMenu}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
let dialpadButton;
|
||||||
|
if (this.state.callState === CallState.Connected && this.props.call.opponentSupportsDTMF()) {
|
||||||
dialpadButton = (
|
dialpadButton = (
|
||||||
<ContextMenuButton
|
<ContextMenuButton
|
||||||
className="mx_CallView_callControls_button mx_CallView_callControls_dialpad"
|
className="mx_CallView_callControls_button mx_CallView_callControls_dialpad"
|
||||||
|
@ -560,7 +546,11 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={callControlsClasses}>
|
<div
|
||||||
|
className={callControlsClasses}
|
||||||
|
onMouseEnter={this.onCallControlsMouseEnter}
|
||||||
|
onMouseLeave={this.onCallControlsMouseLeave}
|
||||||
|
>
|
||||||
{ dialpadButton }
|
{ dialpadButton }
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className={micClasses}
|
className={micClasses}
|
||||||
|
@ -821,10 +811,15 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
{ expandButton }
|
{ expandButton }
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
|
const callTypeIconClassName = classNames("mx_CallView_header_callTypeIcon", {
|
||||||
|
"mx_CallView_header_callTypeIcon_voice": !isVideoCall,
|
||||||
|
"mx_CallView_header_callTypeIcon_video": isVideoCall,
|
||||||
|
});
|
||||||
|
|
||||||
let header: React.ReactNode;
|
let header: React.ReactNode;
|
||||||
if (!this.props.pipMode) {
|
if (!this.props.pipMode) {
|
||||||
header = <div className="mx_CallView_header">
|
header = <div className="mx_CallView_header">
|
||||||
<div className="mx_CallView_header_phoneIcon" />
|
<div className={callTypeIconClassName} />
|
||||||
<span className="mx_CallView_header_callType">{ callTypeText }</span>
|
<span className="mx_CallView_header_callType">{ callTypeText }</span>
|
||||||
{ headerControls }
|
{ headerControls }
|
||||||
</div>;
|
</div>;
|
||||||
|
|
53
src/customisations/WidgetVariables.ts
Normal file
53
src/customisations/WidgetVariables.ts
Normal 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 = {};
|
|
@ -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.",
|
"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.",
|
"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 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",
|
"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",
|
"Send and receive voice messages": "Send and receive voice messages",
|
||||||
"Render LaTeX maths in messages": "Render LaTeX maths in 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.",
|
"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.",
|
"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, 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.",
|
"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 can’t disable this later. Bridges & most bots won’t work yet.": "You can’t disable this later. Bridges & most bots won’t work yet.",
|
"You can’t disable this later. Bridges & most bots won’t work yet.": "You can’t disable this later. Bridges & most bots won’t work yet.",
|
||||||
"Your server requires encryption to be enabled in private rooms.": "Your server requires encryption to be enabled in private rooms.",
|
"Your server requires encryption to be enabled in private rooms.": "Your server requires encryption to be enabled in private rooms.",
|
||||||
|
|
|
@ -181,8 +181,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
||||||
feedbackLabel: "spaces-feedback",
|
feedbackLabel: "spaces-feedback",
|
||||||
extraSettings: [
|
extraSettings: [
|
||||||
"feature_spaces.all_rooms",
|
"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,
|
default: true,
|
||||||
controller: new ReloadOnChangeController(),
|
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": {
|
"feature_dnd": {
|
||||||
isFeature: true,
|
isFeature: true,
|
||||||
displayName: _td("Show options to enable 'Do not disturb' mode"),
|
displayName: _td("Show options to enable 'Do not disturb' mode"),
|
||||||
|
|
|
@ -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
|
// 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 spacesEnabled = SettingsStore.getValue("feature_spaces");
|
||||||
const spacesTweakAllRoomsEnabled = SettingsStore.getValue("feature_spaces.all_rooms");
|
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 homeSpaceKey = spacesTweakAllRoomsEnabled ? "ALL_ROOMS" : "HOME_SPACE";
|
||||||
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || homeSpaceKey}`;
|
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 roomIds = new Set(childRooms.map(r => r.roomId));
|
||||||
const space = this.matrixClient?.getRoom(spaceId);
|
const space = this.matrixClient?.getRoom(spaceId);
|
||||||
|
|
||||||
if (spacesTweakSpaceMemberDMsEnabled) {
|
// Add relevant DMs
|
||||||
// Add relevant DMs
|
space?.getMembers().forEach(member => {
|
||||||
space?.getMembers().forEach(member => {
|
if (member.membership !== "join" && member.membership !== "invite") return;
|
||||||
if (member.membership !== "join" && member.membership !== "invite") return;
|
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
|
||||||
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
|
roomIds.add(roomId);
|
||||||
roomIds.add(roomId);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
const newPath = new Set(parentPath).add(spaceId);
|
const newPath = new Set(parentPath).add(spaceId);
|
||||||
childSpaces.forEach(childSpace => {
|
childSpaces.forEach(childSpace => {
|
||||||
|
@ -568,14 +564,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.spaceFilteredRooms.forEach((roomIds, s) => {
|
this.spaceFilteredRooms.forEach((roomIds, s) => {
|
||||||
// Update NotificationStates
|
// Update NotificationStates
|
||||||
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
|
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
|
||||||
if (roomIds.has(room.roomId)) {
|
if (!roomIds.has(room.roomId)) return false;
|
||||||
if (s !== HOME_SPACE && spacesTweakSpaceDMBadgesEnabled) return true;
|
|
||||||
|
|
||||||
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
|
||||||
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
|
return s === HOME_SPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}, 100, { trailing: true, leading: true });
|
}, 100, { trailing: true, leading: true });
|
||||||
|
@ -878,8 +873,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
export default class SpaceStore {
|
export default class SpaceStore {
|
||||||
public static spacesEnabled = spacesEnabled;
|
public static spacesEnabled = spacesEnabled;
|
||||||
public static spacesTweakAllRoomsEnabled = spacesTweakAllRoomsEnabled;
|
public static spacesTweakAllRoomsEnabled = spacesTweakAllRoomsEnabled;
|
||||||
public static spacesTweakSpaceMemberDMsEnabled = spacesTweakSpaceMemberDMsEnabled;
|
|
||||||
public static spacesTweakSpaceDMBadgesEnabled = spacesTweakSpaceDMBadgesEnabled;
|
|
||||||
|
|
||||||
private static internalInstance = new SpaceStoreClass();
|
private static internalInstance = new SpaceStoreClass();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { NOTIFICATION_STATE_UPDATE, NotificationState } from "./NotificationStat
|
||||||
import { FetchRoomFn } from "./ListNotificationState";
|
import { FetchRoomFn } from "./ListNotificationState";
|
||||||
|
|
||||||
export class SpaceNotificationState extends NotificationState {
|
export class SpaceNotificationState extends NotificationState {
|
||||||
private rooms: Room[] = [];
|
public rooms: Room[] = []; // exposed only for tests
|
||||||
private states: { [spaceId: string]: RoomNotificationState } = {};
|
private states: { [spaceId: string]: RoomNotificationState } = {};
|
||||||
|
|
||||||
constructor(private spaceId: string | symbol, private getRoomFn: FetchRoomFn) {
|
constructor(private spaceId: string | symbol, private getRoomFn: FetchRoomFn) {
|
||||||
|
|
|
@ -54,6 +54,7 @@ import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { ELEMENT_CLIENT_ID } from "../../identifiers";
|
import { ELEMENT_CLIENT_ID } from "../../identifiers";
|
||||||
import { getUserLanguage } from "../../languageHandler";
|
import { getUserLanguage } from "../../languageHandler";
|
||||||
|
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
|
||||||
|
|
||||||
// TODO: Destroy all of this code
|
// TODO: Destroy all of this code
|
||||||
|
|
||||||
|
@ -191,7 +192,8 @@ export class StopGapWidget extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private runUrlTemplate(opts = { asPopout: false }): string {
|
private runUrlTemplate(opts = { asPopout: false }): string {
|
||||||
const templated = this.mockWidget.getCompleteUrl({
|
const fromCustomisation = WidgetVariableCustomisations?.provideVariables?.() ?? {};
|
||||||
|
const defaults: ITemplateParams = {
|
||||||
widgetRoomId: this.roomId,
|
widgetRoomId: this.roomId,
|
||||||
currentUserId: MatrixClientPeg.get().getUserId(),
|
currentUserId: MatrixClientPeg.get().getUserId(),
|
||||||
userDisplayName: OwnProfileStore.instance.displayName,
|
userDisplayName: OwnProfileStore.instance.displayName,
|
||||||
|
@ -199,7 +201,8 @@ export class StopGapWidget extends EventEmitter {
|
||||||
clientId: ELEMENT_CLIENT_ID,
|
clientId: ELEMENT_CLIENT_ID,
|
||||||
clientTheme: SettingsStore.getValue("theme"),
|
clientTheme: SettingsStore.getValue("theme"),
|
||||||
clientLanguage: getUserLanguage(),
|
clientLanguage: getUserLanguage(),
|
||||||
}, opts?.asPopout);
|
};
|
||||||
|
const templated = this.mockWidget.getCompleteUrl(Object.assign(defaults, fromCustomisation), opts?.asPopout);
|
||||||
|
|
||||||
const parsed = new URL(templated);
|
const parsed = new URL(templated);
|
||||||
|
|
||||||
|
@ -363,6 +366,9 @@ export class StopGapWidget extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async prepare(): Promise<void> {
|
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;
|
if (this.scalarToken) return;
|
||||||
const existingMessaging = WidgetMessagingStore.instance.getMessaging(this.mockWidget);
|
const existingMessaging = WidgetMessagingStore.instance.getMessaging(this.mockWidget);
|
||||||
if (existingMessaging) this.messaging = existingMessaging;
|
if (existingMessaging) this.messaging = existingMessaging;
|
||||||
|
|
|
@ -19,5 +19,3 @@ limitations under the License.
|
||||||
|
|
||||||
localStorage.setItem("mx_labs_feature_feature_spaces", "true");
|
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.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");
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/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 "./SpaceStore-setup"; // enable space lab
|
||||||
import "../skinned-sdk"; // Must be first for skinning to work
|
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 testUserId = "@test:user";
|
||||||
|
|
||||||
const getUserIdForRoomId = jest.fn();
|
const getUserIdForRoomId = jest.fn();
|
||||||
|
const getDMRoomsForUserId = jest.fn();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
DMRoomMap.sharedInstance = { getUserIdForRoomId };
|
DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId };
|
||||||
|
|
||||||
const fav1 = "!fav1:server";
|
const fav1 = "!fav1:server";
|
||||||
const fav2 = "!fav2:server";
|
const fav2 = "!fav2:server";
|
||||||
const fav3 = "!fav3:server";
|
const fav3 = "!fav3:server";
|
||||||
const dm1 = "!dm1:server";
|
const dm1 = "!dm1:server";
|
||||||
const dm1Partner = "@dm1Partner:server";
|
const dm1Partner = new RoomMember(dm1, "@dm1Partner:server");
|
||||||
|
dm1Partner.membership = "join";
|
||||||
const dm2 = "!dm2:server";
|
const dm2 = "!dm2:server";
|
||||||
const dm2Partner = "@dm2Partner:server";
|
const dm2Partner = new RoomMember(dm2, "@dm2Partner:server");
|
||||||
|
dm2Partner.membership = "join";
|
||||||
const dm3 = "!dm3:server";
|
const dm3 = "!dm3:server";
|
||||||
const dm3Partner = "@dm3Partner:server";
|
const dm3Partner = new RoomMember(dm3, "@dm3Partner:server");
|
||||||
|
dm3Partner.membership = "join";
|
||||||
const orphan1 = "!orphan1:server";
|
const orphan1 = "!orphan1:server";
|
||||||
const orphan2 = "!orphan2:server";
|
const orphan2 = "!orphan2:server";
|
||||||
const invite1 = "!invite1:server";
|
const invite1 = "!invite1:server";
|
||||||
|
@ -320,11 +325,40 @@ describe("SpaceStore", () => {
|
||||||
|
|
||||||
getUserIdForRoomId.mockImplementation(roomId => {
|
getUserIdForRoomId.mockImplementation(roomId => {
|
||||||
return {
|
return {
|
||||||
[dm1]: dm1Partner,
|
[dm1]: dm1Partner.userId,
|
||||||
[dm2]: dm2Partner,
|
[dm2]: dm2Partner.userId,
|
||||||
[dm3]: dm3Partner,
|
[dm3]: dm3Partner.userId,
|
||||||
}[roomId];
|
}[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();
|
await run();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -375,6 +409,66 @@ describe("SpaceStore", () => {
|
||||||
const space = client.getRoom(space3);
|
const space = client.getRoom(space3);
|
||||||
expect(store.getSpaceFilteredRoomIds(space).has(invite2)).toBeTruthy();
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue