mirror of
https://github.com/element-hq/element-web
synced 2024-11-24 02:05:45 +03:00
🧵 Enable threads by default (#9736)
* Delabs threads * remove threads reload when labs is toggled * Fix ts strict * fix rebase mistake * remove .only * fix pr comments * re-introduce backwards compat * Fix export test * Fix SearchREsultTile test * strict ts
This commit is contained in:
parent
9668a24ca7
commit
2d2755d145
32 changed files with 88 additions and 170 deletions
|
@ -77,7 +77,6 @@ describe("Polls", () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.enableLabsFeature("feature_thread");
|
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,17 +19,10 @@ limitations under the License.
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { SynapseInstance } from "../../plugins/synapsedocker";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
|
|
||||||
function markWindowBeforeReload(): void {
|
|
||||||
// mark our window object to "know" when it gets reloaded
|
|
||||||
cy.window().then((w) => (w.beforeReload = true));
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Threads", () => {
|
describe("Threads", () => {
|
||||||
let synapse: SynapseInstance;
|
let synapse: SynapseInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Default threads to ON for this spec
|
|
||||||
cy.enableLabsFeature("feature_thread");
|
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
|
@ -44,35 +37,6 @@ describe("Threads", () => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopSynapse(synapse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should reload when enabling threads beta", () => {
|
|
||||||
markWindowBeforeReload();
|
|
||||||
|
|
||||||
// Turn off
|
|
||||||
cy.openUserSettings("Labs").within(() => {
|
|
||||||
// initially the new property is there
|
|
||||||
cy.window().should("have.prop", "beforeReload", true);
|
|
||||||
|
|
||||||
cy.leaveBeta("Threads");
|
|
||||||
cy.wait(1000);
|
|
||||||
// after reload the property should be gone
|
|
||||||
cy.window().should("not.have.prop", "beforeReload");
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(".mx_MatrixChat", { timeout: 15000 }); // wait for the app
|
|
||||||
markWindowBeforeReload();
|
|
||||||
|
|
||||||
// Turn on
|
|
||||||
cy.openUserSettings("Labs").within(() => {
|
|
||||||
// initially the new property is there
|
|
||||||
cy.window().should("have.prop", "beforeReload", true);
|
|
||||||
|
|
||||||
cy.joinBeta("Threads");
|
|
||||||
cy.wait(1000);
|
|
||||||
// after reload the property should be gone
|
|
||||||
cy.window().should("not.have.prop", "beforeReload");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be usable for a conversation", () => {
|
it("should be usable for a conversation", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, {
|
cy.getBot(synapse, {
|
||||||
|
|
|
@ -118,13 +118,6 @@ limitations under the License.
|
||||||
color: $primary-content;
|
color: $primary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_MessageActionBar_threadButton {
|
|
||||||
.mx_Indicator {
|
|
||||||
background: $links;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mx_MessageActionBar_favouriteButton_fillstar {
|
&.mx_MessageActionBar_favouriteButton_fillstar {
|
||||||
color: var(--MessageActionBar-star-button-color);
|
color: var(--MessageActionBar-star-button-color);
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 85 KiB |
|
@ -233,7 +233,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
opts.pendingEventOrdering = PendingEventOrdering.Detached;
|
opts.pendingEventOrdering = PendingEventOrdering.Detached;
|
||||||
opts.lazyLoadMembers = true;
|
opts.lazyLoadMembers = true;
|
||||||
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
|
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
|
||||||
opts.experimentalThreadSupport = SettingsStore.getValue("feature_thread");
|
opts.experimentalThreadSupport = SettingsStore.getValue("feature_threadstable");
|
||||||
|
|
||||||
if (SettingsStore.getValue("feature_sliding_sync")) {
|
if (SettingsStore.getValue("feature_sliding_sync")) {
|
||||||
const proxyUrl = SettingsStore.getValue("feature_sliding_sync_proxy_url");
|
const proxyUrl = SettingsStore.getValue("feature_sliding_sync_proxy_url");
|
||||||
|
|
|
@ -287,7 +287,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
// and we check this in a hot code path. This is also cached in our
|
// and we check this in a hot code path. This is also cached in our
|
||||||
// RoomContext, however we still need a fallback for roomless MessagePanels.
|
// RoomContext, however we still need a fallback for roomless MessagePanels.
|
||||||
this._showHiddenEvents = SettingsStore.getValue("showHiddenEventsInTimeline");
|
this._showHiddenEvents = SettingsStore.getValue("showHiddenEventsInTimeline");
|
||||||
this.threadsEnabled = SettingsStore.getValue("feature_thread");
|
this.threadsEnabled = SettingsStore.getValue("feature_threadstable");
|
||||||
|
|
||||||
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
|
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
|
||||||
"showTypingNotifications",
|
"showTypingNotifications",
|
||||||
|
|
|
@ -33,6 +33,7 @@ import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
||||||
import RoomContext from "../../contexts/RoomContext";
|
import RoomContext from "../../contexts/RoomContext";
|
||||||
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
let debuglog = function (msg: string) {};
|
let debuglog = function (msg: string) {};
|
||||||
|
@ -98,7 +99,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||||
return b.length - a.length;
|
return b.length - a.length;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (client.supportsExperimentalThreads()) {
|
if (SettingsStore.getValue("feature_threadstable")) {
|
||||||
// Process all thread roots returned in this batch of search results
|
// Process all thread roots returned in this batch of search results
|
||||||
// XXX: This won't work for results coming from Seshat which won't include the bundled relationship
|
// XXX: This won't work for results coming from Seshat which won't include the bundled relationship
|
||||||
for (const result of results.results) {
|
for (const result of results.results) {
|
||||||
|
|
|
@ -1177,7 +1177,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
CHAT_EFFECTS.forEach((effect) => {
|
CHAT_EFFECTS.forEach((effect) => {
|
||||||
if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) {
|
if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) {
|
||||||
// For initial threads launch, chat effects are disabled see #19731
|
// For initial threads launch, chat effects are disabled see #19731
|
||||||
if (!SettingsStore.getValue("feature_thread") || !ev.isRelation(THREAD_RELATION_TYPE.name)) {
|
if (!SettingsStore.getValue("feature_threadstable") || !ev.isRelation(THREAD_RELATION_TYPE.name)) {
|
||||||
dis.dispatch({ action: `effects.${effect.command}` });
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,7 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
|
||||||
const openFeedback = shouldShowFeedback()
|
const openFeedback = shouldShowFeedback()
|
||||||
? () => {
|
? () => {
|
||||||
Modal.createDialog(BetaFeedbackDialog, {
|
Modal.createDialog(BetaFeedbackDialog, {
|
||||||
featureId: "feature_thread",
|
featureId: "feature_threadstable",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
|
@ -1683,7 +1683,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
is very tied to the main room timeline, we are forcing the timeline to
|
is very tied to the main room timeline, we are forcing the timeline to
|
||||||
send read receipts for threaded events */
|
send read receipts for threaded events */
|
||||||
const isThreadTimeline = this.context.timelineRenderingType === TimelineRenderingType.Thread;
|
const isThreadTimeline = this.context.timelineRenderingType === TimelineRenderingType.Thread;
|
||||||
if (SettingsStore.getValue("feature_thread") && isThreadTimeline) {
|
if (SettingsStore.getValue("feature_threadstable") && isThreadTimeline) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const index = this.state.events.findIndex((ev) => ev.getId() === evId);
|
const index = this.state.events.findIndex((ev) => ev.getId() === evId);
|
||||||
|
|
|
@ -71,11 +71,7 @@ const ReplyInThreadButton = ({ mxEvent, closeMenu }: IReplyInThreadButton) => {
|
||||||
if (Boolean(relationType) && relationType !== RelationType.Thread) return null;
|
if (Boolean(relationType) && relationType !== RelationType.Thread) return null;
|
||||||
|
|
||||||
const onClick = (): void => {
|
const onClick = (): void => {
|
||||||
if (!localStorage.getItem("mx_seen_feature_thread")) {
|
if (!SettingsStore.getValue("feature_threadstable")) {
|
||||||
localStorage.setItem("mx_seen_feature_thread", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SettingsStore.getValue("feature_thread")) {
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ViewUserSettings,
|
action: Action.ViewUserSettings,
|
||||||
initialTabId: UserTab.Labs,
|
initialTabId: UserTab.Labs,
|
||||||
|
@ -644,7 +640,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
rightClick &&
|
rightClick &&
|
||||||
contentActionable &&
|
contentActionable &&
|
||||||
canSendMessages &&
|
canSendMessages &&
|
||||||
SettingsStore.getValue("feature_thread") &&
|
SettingsStore.getValue("feature_threadstable") &&
|
||||||
Thread.hasServerSideSupport &&
|
Thread.hasServerSideSupport &&
|
||||||
timelineRenderingType !== TimelineRenderingType.Thread
|
timelineRenderingType !== TimelineRenderingType.Thread
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -56,7 +56,6 @@ import { Key } from "../../../Keyboard";
|
||||||
import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts";
|
import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts";
|
||||||
import { UserTab } from "../dialogs/UserTab";
|
import { UserTab } from "../dialogs/UserTab";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
|
||||||
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
||||||
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
|
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
|
||||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||||
|
@ -204,8 +203,7 @@ const ReplyInThreadButton = ({ mxEvent }: IReplyInThreadButton) => {
|
||||||
|
|
||||||
const relationType = mxEvent?.getRelation()?.rel_type;
|
const relationType = mxEvent?.getRelation()?.rel_type;
|
||||||
const hasARelation = !!relationType && relationType !== RelationType.Thread;
|
const hasARelation = !!relationType && relationType !== RelationType.Thread;
|
||||||
const firstTimeSeeingThreads = !localStorage.getItem("mx_seen_feature_thread");
|
const threadsEnabled = SettingsStore.getValue("feature_threadstable");
|
||||||
const threadsEnabled = SettingsStore.getValue("feature_thread");
|
|
||||||
|
|
||||||
if (!threadsEnabled && !Thread.hasServerSideSupport) {
|
if (!threadsEnabled && !Thread.hasServerSideSupport) {
|
||||||
// hide the prompt if the user would only have degraded mode
|
// hide the prompt if the user would only have degraded mode
|
||||||
|
@ -217,11 +215,7 @@ const ReplyInThreadButton = ({ mxEvent }: IReplyInThreadButton) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
if (firstTimeSeeingThreads) {
|
if (!SettingsStore.getValue("feature_threadstable")) {
|
||||||
localStorage.setItem("mx_seen_feature_thread", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SettingsStore.getValue("feature_thread")) {
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ViewUserSettings,
|
action: Action.ViewUserSettings,
|
||||||
initialTabId: UserTab.Labs,
|
initialTabId: UserTab.Labs,
|
||||||
|
@ -257,7 +251,7 @@ const ReplyInThreadButton = ({ mxEvent }: IReplyInThreadButton) => {
|
||||||
</div>
|
</div>
|
||||||
{!hasARelation && (
|
{!hasARelation && (
|
||||||
<div className="mx_Tooltip_sub">
|
<div className="mx_Tooltip_sub">
|
||||||
{SettingsStore.getValue("feature_thread")
|
{SettingsStore.getValue("feature_threadstable")
|
||||||
? _t("Beta feature")
|
? _t("Beta feature")
|
||||||
: _t("Beta feature. Click to learn more.")}
|
: _t("Beta feature. Click to learn more.")}
|
||||||
</div>
|
</div>
|
||||||
|
@ -273,7 +267,6 @@ const ReplyInThreadButton = ({ mxEvent }: IReplyInThreadButton) => {
|
||||||
onContextMenu={onClick}
|
onContextMenu={onClick}
|
||||||
>
|
>
|
||||||
<ThreadIcon />
|
<ThreadIcon />
|
||||||
{firstTimeSeeingThreads && !threadsEnabled && <div className="mx_Indicator" />}
|
|
||||||
</RovingAccessibleTooltipButton>
|
</RovingAccessibleTooltipButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -393,21 +386,6 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
||||||
private readonly forbiddenThreadHeadMsgType = [MsgType.KeyVerificationRequest];
|
private readonly forbiddenThreadHeadMsgType = [MsgType.KeyVerificationRequest];
|
||||||
|
|
||||||
private get showReplyInThreadAction(): boolean {
|
private get showReplyInThreadAction(): boolean {
|
||||||
if (!SettingsStore.getValue("feature_thread") && !Thread.hasServerSideSupport) {
|
|
||||||
// hide the prompt if the user would only have degraded mode
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!SettingsStore.getBetaInfo("feature_thread") &&
|
|
||||||
!SettingsStore.getValue("feature_thread") &&
|
|
||||||
!SdkConfig.get("show_labs_settings")
|
|
||||||
) {
|
|
||||||
// Hide the beta prompt if there is no UI to enable it,
|
|
||||||
// e.g if config.json disables it and doesn't enable show labs flags
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const inNotThreadTimeline = this.context.timelineRenderingType !== TimelineRenderingType.Thread;
|
const inNotThreadTimeline = this.context.timelineRenderingType !== TimelineRenderingType.Thread;
|
||||||
|
|
||||||
const isAllowedMessageType =
|
const isAllowedMessageType =
|
||||||
|
@ -568,7 +546,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
SettingsStore.getValue("feature_thread") &&
|
SettingsStore.getValue("feature_threadstable") &&
|
||||||
// Show thread icon even for deleted messages, but only within main timeline
|
// Show thread icon even for deleted messages, but only within main timeline
|
||||||
this.context.timelineRenderingType === TimelineRenderingType.Room &&
|
this.context.timelineRenderingType === TimelineRenderingType.Room &&
|
||||||
this.props.mxEvent.getThread()
|
this.props.mxEvent.getThread()
|
||||||
|
|
|
@ -297,7 +297,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
);
|
);
|
||||||
rightPanelPhaseButtons.set(
|
rightPanelPhaseButtons.set(
|
||||||
RightPanelPhases.ThreadPanel,
|
RightPanelPhases.ThreadPanel,
|
||||||
SettingsStore.getValue("feature_thread") ? (
|
SettingsStore.getValue("feature_threadstable") ? (
|
||||||
<HeaderButton
|
<HeaderButton
|
||||||
key={RightPanelPhases.ThreadPanel}
|
key={RightPanelPhases.ThreadPanel}
|
||||||
name="threadsButton"
|
name="threadsButton"
|
||||||
|
|
|
@ -387,7 +387,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SettingsStore.getValue("feature_thread")) {
|
if (SettingsStore.getValue("feature_threadstable")) {
|
||||||
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
|
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
|
||||||
|
|
||||||
if (this.thread && !this.supportsThreadNotifications) {
|
if (this.thread && !this.supportsThreadNotifications) {
|
||||||
|
@ -469,7 +469,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
if (this.props.showReactions) {
|
if (this.props.showReactions) {
|
||||||
this.props.mxEvent.removeListener(MatrixEventEvent.RelationsCreated, this.onReactionsCreated);
|
this.props.mxEvent.removeListener(MatrixEventEvent.RelationsCreated, this.onReactionsCreated);
|
||||||
}
|
}
|
||||||
if (SettingsStore.getValue("feature_thread")) {
|
if (SettingsStore.getValue("feature_threadstable")) {
|
||||||
this.props.mxEvent.off(ThreadEvent.Update, this.updateThread);
|
this.props.mxEvent.off(ThreadEvent.Update, this.updateThread);
|
||||||
}
|
}
|
||||||
this.threadState?.off(NotificationStateEvents.Update, this.onThreadStateUpdate);
|
this.threadState?.off(NotificationStateEvents.Update, this.onThreadStateUpdate);
|
||||||
|
@ -496,7 +496,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
};
|
};
|
||||||
|
|
||||||
private get thread(): Thread | null {
|
private get thread(): Thread | null {
|
||||||
if (!SettingsStore.getValue("feature_thread")) {
|
if (!SettingsStore.getValue("feature_threadstable")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default class SearchResultTile extends React.Component<IProps> {
|
||||||
const layout = SettingsStore.getValue("layout");
|
const layout = SettingsStore.getValue("layout");
|
||||||
const isTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
|
const isTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
|
||||||
const alwaysShowTimestamps = SettingsStore.getValue("alwaysShowTimestamps");
|
const alwaysShowTimestamps = SettingsStore.getValue("alwaysShowTimestamps");
|
||||||
const threadsEnabled = SettingsStore.getValue("feature_thread");
|
const threadsEnabled = SettingsStore.getValue("feature_threadstable");
|
||||||
|
|
||||||
const timeline = result.context.getTimeline();
|
const timeline = result.context.getTimeline();
|
||||||
for (let j = 0; j < timeline.length; j++) {
|
for (let j = 0; j < timeline.length; j++) {
|
||||||
|
|
|
@ -436,7 +436,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||||
// For initial threads launch, chat effects are disabled
|
// For initial threads launch, chat effects are disabled
|
||||||
// see #19731
|
// see #19731
|
||||||
const isNotThread = this.props.relation?.rel_type !== THREAD_RELATION_TYPE.name;
|
const isNotThread = this.props.relation?.rel_type !== THREAD_RELATION_TYPE.name;
|
||||||
if (!SettingsStore.getValue("feature_thread") || isNotThread) {
|
if (!SettingsStore.getValue("feature_threadstable") || isNotThread) {
|
||||||
dis.dispatch({ action: `effects.${effect.command}` });
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ export function sendMessage(message: string, isHTML: boolean, { roomContext, mxC
|
||||||
// For initial threads launch, chat effects are disabled
|
// For initial threads launch, chat effects are disabled
|
||||||
// see #19731
|
// see #19731
|
||||||
const isNotThread = relation?.rel_type !== THREAD_RELATION_TYPE.name;
|
const isNotThread = relation?.rel_type !== THREAD_RELATION_TYPE.name;
|
||||||
if (!SettingsStore.getValue("feature_thread") || isNotThread) {
|
if (!SettingsStore.getValue("feature_threadstable") || isNotThread) {
|
||||||
dis.dispatch({ action: `effects.${effect.command}` });
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -915,15 +915,9 @@
|
||||||
"In rooms that support moderation, the “Report” button will let you report abuse to room moderators.": "In rooms that support moderation, the “Report” button will let you report abuse to room moderators.",
|
"In rooms that support moderation, the “Report” button will let you report abuse to room moderators.": "In rooms that support moderation, the “Report” button will let you report abuse to room moderators.",
|
||||||
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
|
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
|
||||||
"Message Pinning": "Message Pinning",
|
"Message Pinning": "Message Pinning",
|
||||||
"Threaded messaging": "Threaded messaging",
|
"Threaded messages": "Threaded messages",
|
||||||
"Keep discussions organised with threads.": "Keep discussions organised with threads.",
|
"Keep discussions organised with threads.": "Keep discussions organised with threads.",
|
||||||
"Threads help keep conversations on-topic and easy to track. <a>Learn more</a>.": "Threads help keep conversations on-topic and easy to track. <a>Learn more</a>.",
|
"Threads help keep conversations on-topic and easy to track. <a>Learn more</a>.": "Threads help keep conversations on-topic and easy to track. <a>Learn more</a>.",
|
||||||
"How can I start a thread?": "How can I start a thread?",
|
|
||||||
"Use “%(replyInThread)s” when hovering over a message.": "Use “%(replyInThread)s” when hovering over a message.",
|
|
||||||
"Reply in thread": "Reply in thread",
|
|
||||||
"How can I leave the beta?": "How can I leave the beta?",
|
|
||||||
"To leave, return to this page and use the “%(leaveTheBeta)s” button.": "To leave, return to this page and use the “%(leaveTheBeta)s” button.",
|
|
||||||
"Leave the beta": "Leave the beta",
|
|
||||||
"Rich text editor": "Rich text editor",
|
"Rich text editor": "Rich text editor",
|
||||||
"Use rich text instead of Markdown in the message composer. Plain text mode coming soon.": "Use rich text instead of Markdown in the message composer. Plain text mode coming soon.",
|
"Use rich text instead of Markdown in the message composer. Plain text mode coming soon.": "Use rich text instead of Markdown in the message composer. Plain text mode coming soon.",
|
||||||
"Render simple counters in room header": "Render simple counters in room header",
|
"Render simple counters in room header": "Render simple counters in room header",
|
||||||
|
@ -2322,6 +2316,7 @@
|
||||||
"Error processing audio message": "Error processing audio message",
|
"Error processing audio message": "Error processing audio message",
|
||||||
"View live location": "View live location",
|
"View live location": "View live location",
|
||||||
"React": "React",
|
"React": "React",
|
||||||
|
"Reply in thread": "Reply in thread",
|
||||||
"Can't create a thread from an event with an existing relation": "Can't create a thread from an event with an existing relation",
|
"Can't create a thread from an event with an existing relation": "Can't create a thread from an event with an existing relation",
|
||||||
"Beta feature": "Beta feature",
|
"Beta feature": "Beta feature",
|
||||||
"Beta feature. Click to learn more.": "Beta feature. Click to learn more.",
|
"Beta feature. Click to learn more.": "Beta feature. Click to learn more.",
|
||||||
|
@ -3198,6 +3193,7 @@
|
||||||
"Beta": "Beta",
|
"Beta": "Beta",
|
||||||
"Leaving the beta will reload %(brand)s.": "Leaving the beta will reload %(brand)s.",
|
"Leaving the beta will reload %(brand)s.": "Leaving the beta will reload %(brand)s.",
|
||||||
"Joining the beta will reload %(brand)s.": "Joining the beta will reload %(brand)s.",
|
"Joining the beta will reload %(brand)s.": "Joining the beta will reload %(brand)s.",
|
||||||
|
"Leave the beta": "Leave the beta",
|
||||||
"Join the beta": "Join the beta",
|
"Join the beta": "Join the beta",
|
||||||
"Updated %(humanizedUpdateTime)s": "Updated %(humanizedUpdateTime)s",
|
"Updated %(humanizedUpdateTime)s": "Updated %(humanizedUpdateTime)s",
|
||||||
"Live until %(expiryTime)s": "Live until %(expiryTime)s",
|
"Live until %(expiryTime)s": "Live until %(expiryTime)s",
|
||||||
|
|
|
@ -255,15 +255,15 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
supportedLevels: LEVELS_FEATURE,
|
supportedLevels: LEVELS_FEATURE,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
"feature_thread": {
|
"feature_threadstable": {
|
||||||
isFeature: true,
|
isFeature: true,
|
||||||
labsGroup: LabGroup.Messaging,
|
labsGroup: LabGroup.Messaging,
|
||||||
controller: new ThreadBetaController(),
|
controller: new ThreadBetaController(),
|
||||||
displayName: _td("Threaded messaging"),
|
displayName: _td("Threaded messages"),
|
||||||
supportedLevels: LEVELS_FEATURE,
|
supportedLevels: LEVELS_FEATURE,
|
||||||
default: false,
|
default: true,
|
||||||
betaInfo: {
|
betaInfo: {
|
||||||
title: _td("Threads"),
|
title: _td("Threaded messages"),
|
||||||
caption: () => (
|
caption: () => (
|
||||||
<>
|
<>
|
||||||
<p>{_t("Keep discussions organised with threads.")}</p>
|
<p>{_t("Keep discussions organised with threads.")}</p>
|
||||||
|
@ -282,28 +282,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
faq: () =>
|
|
||||||
SdkConfig.get().bug_report_endpoint_url && (
|
|
||||||
<>
|
|
||||||
<h4>{_t("How can I start a thread?")}</h4>
|
|
||||||
<p>
|
|
||||||
{_t("Use “%(replyInThread)s” when hovering over a message.", {
|
|
||||||
replyInThread: _t("Reply in thread"),
|
|
||||||
})}
|
|
||||||
</p>
|
|
||||||
<h4>{_t("How can I leave the beta?")}</h4>
|
|
||||||
<p>
|
|
||||||
{_t("To leave, return to this page and use the “%(leaveTheBeta)s” button.", {
|
|
||||||
leaveTheBeta: _t("Leave the beta"),
|
|
||||||
})}
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
feedbackLabel: "thread-feedback",
|
|
||||||
feedbackSubheading: _td(
|
|
||||||
"Thank you for trying the beta, " + "please go into as much detail as you can so we can improve it.",
|
|
||||||
),
|
|
||||||
image: require("../../res/img/betas/threads.png"),
|
|
||||||
requiresRefresh: true,
|
requiresRefresh: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default class TypingStore {
|
||||||
if (SettingsStore.getValue("lowBandwidth")) return;
|
if (SettingsStore.getValue("lowBandwidth")) return;
|
||||||
// Disable typing notification for threads for the initial launch
|
// Disable typing notification for threads for the initial launch
|
||||||
// before we figure out a better user experience for them
|
// before we figure out a better user experience for them
|
||||||
if (SettingsStore.getValue("feature_thread") && threadId) return;
|
if (SettingsStore.getValue("feature_threadstable") && threadId) return;
|
||||||
|
|
||||||
let currentTyping = this.typingStates[roomId];
|
let currentTyping = this.typingStates[roomId];
|
||||||
if ((!isTyping && !currentTyping) || (currentTyping && currentTyping.isTyping === isTyping)) {
|
if ((!isTyping && !currentTyping) || (currentTyping && currentTyping.isTyping === isTyping)) {
|
||||||
|
|
|
@ -278,10 +278,10 @@ export default class RightPanelStore extends ReadyWatchingStore {
|
||||||
// (A nicer fix could be to indicate, that the right panel is loading if there is missing state data and re-emit if the data is available)
|
// (A nicer fix could be to indicate, that the right panel is loading if there is missing state data and re-emit if the data is available)
|
||||||
switch (card.phase) {
|
switch (card.phase) {
|
||||||
case RightPanelPhases.ThreadPanel:
|
case RightPanelPhases.ThreadPanel:
|
||||||
if (!SettingsStore.getValue("feature_thread")) return false;
|
if (!SettingsStore.getValue("feature_threadstable")) return false;
|
||||||
break;
|
break;
|
||||||
case RightPanelPhases.ThreadView:
|
case RightPanelPhases.ThreadView:
|
||||||
if (!SettingsStore.getValue("feature_thread")) return false;
|
if (!SettingsStore.getValue("feature_threadstable")) return false;
|
||||||
if (!card.state.threadHeadEvent) {
|
if (!card.state.threadHeadEvent) {
|
||||||
logger.warn("removed card from right panel because of missing threadHeadEvent in card state");
|
logger.warn("removed card from right panel because of missing threadHeadEvent in card state");
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
// For initial threads launch, chat effects are disabled
|
// For initial threads launch, chat effects are disabled
|
||||||
// see #19731
|
// see #19731
|
||||||
const isNotThread = content["m.relates_to"].rel_type !== THREAD_RELATION_TYPE.name;
|
const isNotThread = content["m.relates_to"].rel_type !== THREAD_RELATION_TYPE.name;
|
||||||
if (!SettingsStore.getValue("feature_thread") || isNotThread) {
|
if (!SettingsStore.getValue("feature_threadstable") || isNotThread) {
|
||||||
dis.dispatch({ action: `effects.${effect.command}` });
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,7 @@ export function makeReplyMixIn(ev?: MatrixEvent): IEventRelation {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ev.threadRootId) {
|
if (ev.threadRootId) {
|
||||||
if (SettingsStore.getValue("feature_thread")) {
|
if (SettingsStore.getValue("feature_threadstable")) {
|
||||||
mixin.is_falling_back = false;
|
mixin.is_falling_back = false;
|
||||||
} else {
|
} else {
|
||||||
// Clients that do not offer a threading UI should behave as follows when replying, for best interaction
|
// Clients that do not offer a threading UI should behave as follows when replying, for best interaction
|
||||||
|
@ -203,7 +203,7 @@ export function shouldDisplayReply(event: MatrixEvent): boolean {
|
||||||
|
|
||||||
const relation = event.getRelation();
|
const relation = event.getRelation();
|
||||||
if (
|
if (
|
||||||
SettingsStore.getValue("feature_thread") &&
|
SettingsStore.getValue("feature_threadstable") &&
|
||||||
relation?.rel_type === THREAD_RELATION_TYPE.name &&
|
relation?.rel_type === THREAD_RELATION_TYPE.name &&
|
||||||
relation?.is_falling_back
|
relation?.is_falling_back
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
this.mediaOmitText = !this.exportOptions.attachmentsIncluded
|
this.mediaOmitText = !this.exportOptions.attachmentsIncluded
|
||||||
? _t("Media omitted")
|
? _t("Media omitted")
|
||||||
: _t("Media omitted - file size limit exceeded");
|
: _t("Media omitted - file size limit exceeded");
|
||||||
this.threadsEnabled = SettingsStore.getValue("feature_thread");
|
this.threadsEnabled = SettingsStore.getValue("feature_threadstable");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getRoomAvatar() {
|
protected async getRoomAvatar() {
|
||||||
|
|
|
@ -169,6 +169,7 @@ describe("TimelinePanel", () => {
|
||||||
const getValueCopy = SettingsStore.getValue;
|
const getValueCopy = SettingsStore.getValue;
|
||||||
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
||||||
if (name === "sendReadReceipts") return true;
|
if (name === "sendReadReceipts") return true;
|
||||||
|
if (name === "feature_threadstable") return false;
|
||||||
return getValueCopy(name);
|
return getValueCopy(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -182,6 +183,7 @@ describe("TimelinePanel", () => {
|
||||||
const getValueCopy = SettingsStore.getValue;
|
const getValueCopy = SettingsStore.getValue;
|
||||||
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
||||||
if (name === "sendReadReceipts") return false;
|
if (name === "sendReadReceipts") return false;
|
||||||
|
if (name === "feature_threadstable") return false;
|
||||||
return getValueCopy(name);
|
return getValueCopy(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -358,7 +360,7 @@ describe("TimelinePanel", () => {
|
||||||
client.supportsExperimentalThreads = () => true;
|
client.supportsExperimentalThreads = () => true;
|
||||||
const getValueCopy = SettingsStore.getValue;
|
const getValueCopy = SettingsStore.getValue;
|
||||||
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
||||||
if (name === "feature_thread") return true;
|
if (name === "feature_threadstable") return true;
|
||||||
return getValueCopy(name);
|
return getValueCopy(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -386,6 +386,12 @@ describe("<MessageActionBar />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when threads feature is not enabled", () => {
|
describe("when threads feature is not enabled", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(setting) => setting !== "feature_threadstable",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("does not render thread button when threads does not have server support", () => {
|
it("does not render thread button when threads does not have server support", () => {
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||||
Thread.setServerSideSupport(FeatureSupport.None);
|
Thread.setServerSideSupport(FeatureSupport.None);
|
||||||
|
@ -416,7 +422,9 @@ describe("<MessageActionBar />", () => {
|
||||||
|
|
||||||
describe("when threads feature is enabled", () => {
|
describe("when threads feature is enabled", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => setting === "feature_thread");
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(setting) => setting === "feature_threadstable",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders thread button on own actionable event", () => {
|
it("renders thread button on own actionable event", () => {
|
||||||
|
|
|
@ -40,7 +40,7 @@ describe("RoomHeaderButtons-test.tsx", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
|
||||||
if (name === "feature_thread") return true;
|
if (name === "feature_threadstable") return true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ describe("EventTile", () => {
|
||||||
|
|
||||||
jest.spyOn(client, "getRoom").mockReturnValue(room);
|
jest.spyOn(client, "getRoom").mockReturnValue(room);
|
||||||
jest.spyOn(client, "decryptEventIfNeeded").mockResolvedValue();
|
jest.spyOn(client, "decryptEventIfNeeded").mockResolvedValue();
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => name === "feature_thread");
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => name === "feature_threadstable");
|
||||||
|
|
||||||
mxEvent = mkMessage({
|
mxEvent = mkMessage({
|
||||||
room: room.roomId,
|
room: room.roomId,
|
||||||
|
|
|
@ -19,14 +19,21 @@ import { SearchResult } from "matrix-js-sdk/src/models/search-result";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { createTestClient } from "../../../test-utils";
|
import { stubClient } from "../../../test-utils";
|
||||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
|
||||||
import SearchResultTile from "../../../../src/components/views/rooms/SearchResultTile";
|
import SearchResultTile from "../../../../src/components/views/rooms/SearchResultTile";
|
||||||
|
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||||
|
|
||||||
|
const ROOM_ID = "!qPewotXpIctQySfjSy:localhost";
|
||||||
|
|
||||||
describe("SearchResultTile", () => {
|
describe("SearchResultTile", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
MatrixClientPeg.get = () => createTestClient();
|
stubClient();
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
const room = new Room(ROOM_ID, cli, "@bob:example.org");
|
||||||
|
jest.spyOn(cli, "getRoom").mockReturnValue(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Sets up appropriate callEventGrouper for m.call. events", () => {
|
it("Sets up appropriate callEventGrouper for m.call. events", () => {
|
||||||
|
@ -44,7 +51,7 @@ describe("SearchResultTile", () => {
|
||||||
},
|
},
|
||||||
event_id: "$144429830826TWwbB:localhost",
|
event_id: "$144429830826TWwbB:localhost",
|
||||||
origin_server_ts: 1432735824653,
|
origin_server_ts: 1432735824653,
|
||||||
room_id: "!qPewotXpIctQySfjSy:localhost",
|
room_id: ROOM_ID,
|
||||||
sender: "@example:example.org",
|
sender: "@example:example.org",
|
||||||
type: "m.room.message",
|
type: "m.room.message",
|
||||||
unsigned: {
|
unsigned: {
|
||||||
|
@ -59,7 +66,7 @@ describe("SearchResultTile", () => {
|
||||||
{
|
{
|
||||||
type: EventType.CallInvite,
|
type: EventType.CallInvite,
|
||||||
sender: "@user1:server",
|
sender: "@user1:server",
|
||||||
room_id: "!qPewotXpIctQySfjSy:localhost",
|
room_id: ROOM_ID,
|
||||||
origin_server_ts: 1432735824652,
|
origin_server_ts: 1432735824652,
|
||||||
content: { call_id: "call.1" },
|
content: { call_id: "call.1" },
|
||||||
event_id: "$1:server",
|
event_id: "$1:server",
|
||||||
|
@ -69,7 +76,7 @@ describe("SearchResultTile", () => {
|
||||||
{
|
{
|
||||||
type: EventType.CallAnswer,
|
type: EventType.CallAnswer,
|
||||||
sender: "@user2:server",
|
sender: "@user2:server",
|
||||||
room_id: "!qPewotXpIctQySfjSy:localhost",
|
room_id: ROOM_ID,
|
||||||
origin_server_ts: 1432735824654,
|
origin_server_ts: 1432735824654,
|
||||||
content: { call_id: "call.1" },
|
content: { call_id: "call.1" },
|
||||||
event_id: "$2:server",
|
event_id: "$2:server",
|
||||||
|
|
|
@ -80,7 +80,7 @@ exports[`<SecurityUserSettingsTab /> renders settings marked as beta as beta car
|
||||||
class="mx_BetaCard_title"
|
class="mx_BetaCard_title"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Threads
|
Threaded messages
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="mx_BetaCard_betaPill"
|
class="mx_BetaCard_betaPill"
|
||||||
|
@ -124,9 +124,6 @@ exports[`<SecurityUserSettingsTab /> renders settings marked as beta as beta car
|
||||||
>
|
>
|
||||||
Joining the beta will reload .
|
Joining the beta will reload .
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
class="mx_BetaCard_faq"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mx_BetaCard_columns_image_wrapper"
|
class="mx_BetaCard_columns_image_wrapper"
|
||||||
|
@ -134,7 +131,6 @@ exports[`<SecurityUserSettingsTab /> renders settings marked as beta as beta car
|
||||||
<img
|
<img
|
||||||
alt=""
|
alt=""
|
||||||
class="mx_BetaCard_columns_image"
|
class="mx_BetaCard_columns_image"
|
||||||
src="image-file-stub"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { mocked } from "jest-mock";
|
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import TypingStore from "../../src/stores/TypingStore";
|
import TypingStore from "../../src/stores/TypingStore";
|
||||||
|
@ -31,10 +30,6 @@ jest.mock("../../src/settings/SettingsStore", () => ({
|
||||||
describe("TypingStore", () => {
|
describe("TypingStore", () => {
|
||||||
let typingStore: TypingStore;
|
let typingStore: TypingStore;
|
||||||
let mockClient: MatrixClient;
|
let mockClient: MatrixClient;
|
||||||
const settings = {
|
|
||||||
sendTypingNotifications: true,
|
|
||||||
feature_thread: false,
|
|
||||||
};
|
|
||||||
const roomId = "!test:example.com";
|
const roomId = "!test:example.com";
|
||||||
const localRoomId = LOCAL_ROOM_ID_PREFIX + "test";
|
const localRoomId = LOCAL_ROOM_ID_PREFIX + "test";
|
||||||
|
|
||||||
|
@ -45,8 +40,8 @@ describe("TypingStore", () => {
|
||||||
const context = new TestSdkContext();
|
const context = new TestSdkContext();
|
||||||
context.client = mockClient;
|
context.client = mockClient;
|
||||||
typingStore = new TypingStore(context);
|
typingStore = new TypingStore(context);
|
||||||
mocked(SettingsStore.getValue).mockImplementation((setting: string) => {
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
|
||||||
return settings[setting];
|
return name === "sendTypingNotifications";
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,18 @@ interface ITestContent extends IContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("export", function () {
|
describe("export", function () {
|
||||||
|
let mockExportOptions: IExportOptions;
|
||||||
|
let mockRoom: Room;
|
||||||
|
let ts0: number;
|
||||||
|
let events: MatrixEvent[];
|
||||||
|
beforeEach(() => {
|
||||||
stubClient();
|
stubClient();
|
||||||
client = MatrixClientPeg.get();
|
client = MatrixClientPeg.get();
|
||||||
client.getUserId = () => {
|
client.getUserId = () => {
|
||||||
return MY_USER_ID;
|
return MY_USER_ID;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockExportOptions: IExportOptions = {
|
mockExportOptions = {
|
||||||
numberOfMessages: 5,
|
numberOfMessages: 5,
|
||||||
maxSize: 100 * 1024 * 1024,
|
maxSize: 100 * 1024 * 1024,
|
||||||
attachmentsIncluded: false,
|
attachmentsIncluded: false,
|
||||||
|
@ -61,9 +66,11 @@ describe("export", function () {
|
||||||
const room = new Room(generateRoomId(), null, client.getUserId());
|
const room = new Room(generateRoomId(), null, client.getUserId());
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
const mockRoom = createRoom();
|
mockRoom = createRoom();
|
||||||
|
ts0 = Date.now();
|
||||||
const ts0 = Date.now();
|
events = mkEvents();
|
||||||
|
jest.spyOn(client, "getRoom").mockReturnValue(mockRoom);
|
||||||
|
});
|
||||||
|
|
||||||
function mkRedactedEvent(i = 0) {
|
function mkRedactedEvent(i = 0) {
|
||||||
return new MatrixEvent({
|
return new MatrixEvent({
|
||||||
|
@ -218,8 +225,6 @@ describe("export", function () {
|
||||||
return matrixEvents;
|
return matrixEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
const events: MatrixEvent[] = mkEvents();
|
|
||||||
|
|
||||||
it("checks if the export format is valid", function () {
|
it("checks if the export format is valid", function () {
|
||||||
function isValidFormat(format: string): boolean {
|
function isValidFormat(format: string): boolean {
|
||||||
const options: string[] = Object.values(ExportFormat);
|
const options: string[] = Object.values(ExportFormat);
|
||||||
|
|
Loading…
Reference in a new issue