type Actions (#7862)

* type ViewHomPage action

Signed-off-by: Kerry Archibald <kerrya@element.io>

* type spacestore actions

Signed-off-by: Kerry Archibald <kerrya@element.io>

* lint

Signed-off-by: Kerry Archibald <kerrya@element.io>

* add action types

Signed-off-by: Kerry Archibald <kerrya@element.io>

* use new action types in stores

Signed-off-by: Kerry Archibald <kerrya@element.io>

* remove debug change

Signed-off-by: Kerry Archibald <kerrya@element.io>

* stricter keyboard shortcut types

Signed-off-by: Kerry Archibald <kerrya@element.io>

* action comments

Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
Kerry 2022-02-22 11:04:27 +01:00 committed by GitHub
parent 57595bc593
commit 5b8d440406
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 304 additions and 73 deletions

View file

@ -26,6 +26,7 @@ import dis from './dispatcher/dispatcher';
import Modal from './Modal'; import Modal from './Modal';
import { _t } from './languageHandler'; import { _t } from './languageHandler';
import QuestionDialog from "./components/views/dialogs/QuestionDialog"; import QuestionDialog from "./components/views/dialogs/QuestionDialog";
import { Action } from "./dispatcher/actions";
// Regex for what a "safe" or "Matrix-looking" localpart would be. // Regex for what a "safe" or "Matrix-looking" localpart would be.
// TODO: Update as needed for https://github.com/matrix-org/matrix-doc/issues/1514 // TODO: Update as needed for https://github.com/matrix-org/matrix-doc/issues/1514
@ -69,7 +70,7 @@ export async function startAnyRegistrationFlow(
if (proceed) { if (proceed) {
dis.dispatch({ action: 'start_registration', screenAfterLogin: options.screen_after }); dis.dispatch({ action: 'start_registration', screenAfterLogin: options.screen_after });
} else if (options.go_home_on_cancel) { } else if (options.go_home_on_cancel) {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: Action.ViewHomePage });
} else if (options.go_welcome_on_cancel) { } else if (options.go_welcome_on_cancel) {
dis.dispatch({ action: 'view_welcome_page' }); dis.dispatch({ action: 'view_welcome_page' });
} }

View file

@ -17,7 +17,7 @@ limitations under the License.
import { _td } from "../languageHandler"; import { _td } from "../languageHandler";
import { isMac, Key } from "../Keyboard"; import { isMac, Key } from "../Keyboard";
import { ISetting } from "../settings/Settings"; import { IBaseSetting } from "../settings/Settings";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
import IncompatibleController from "../settings/controllers/IncompatibleController"; import IncompatibleController from "../settings/controllers/IncompatibleController";
@ -119,9 +119,20 @@ export enum KeyBindingAction {
ToggleHiddenEventVisibility = 'KeyBinding.toggleHiddenEventVisibility', ToggleHiddenEventVisibility = 'KeyBinding.toggleHiddenEventVisibility',
} }
export type KeyBindingConfig = {
key: string;
ctrlOrCmdKey?: boolean;
ctrlKey?: boolean;
altKey?: boolean;
shiftKey?: boolean;
metaKey?: boolean;
};
type KeyboardShortcutSetting = IBaseSetting<KeyBindingConfig>;
type IKeyboardShortcuts = { type IKeyboardShortcuts = {
// TODO: We should figure out what to do with the keyboard shortcuts that are not handled by KeybindingManager // TODO: We should figure out what to do with the keyboard shortcuts that are not handled by KeybindingManager
[k in (KeyBindingAction | string)]: ISetting; [k in (KeyBindingAction | string)]: KeyboardShortcutSetting;
}; };
export interface ICategory { export interface ICategory {
@ -614,7 +625,11 @@ export const getKeyboardShortcuts = (): IKeyboardShortcuts => {
}, {}); }, {});
}; };
export const registerShortcut = (shortcutName: string, categoryName: CategoryName, shortcut: ISetting): void => { export const registerShortcut = (
shortcutName: string,
categoryName: CategoryName,
shortcut: KeyboardShortcutSetting,
): void => {
KEYBOARD_SHORTCUTS[shortcutName] = shortcut; KEYBOARD_SHORTCUTS[shortcutName] = shortcut;
CATEGORIES[categoryName].settingNames.push(shortcutName); CATEGORIES[categoryName].settingNames.push(shortcutName);
}; };

View file

@ -342,7 +342,7 @@ class FeaturedUser extends React.Component {
e.stopPropagation(); e.stopPropagation();
dis.dispatch({ dis.dispatch({
action: 'view_start_chat_or_reuse', action: Action.ViewStartChatOrReuse,
user_id: this.props.summaryInfo.user_id, user_id: this.props.summaryInfo.user_id,
}); });
}; };
@ -491,7 +491,7 @@ export default class GroupView extends React.Component {
if (this._unmounted || groupId !== errorGroupId) return; if (this._unmounted || groupId !== errorGroupId) return;
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) { if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) {
dis.dispatch({ dis.dispatch({
action: 'do_after_sync_prepared', action: Action.DoAfterSyncPrepared,
deferred_action: { deferred_action: {
action: 'view_group', action: 'view_group',
group_id: groupId, group_id: groupId,

View file

@ -490,7 +490,7 @@ class LoggedInView extends React.Component<IProps, IState> {
break; break;
case KeyBindingAction.GoToHome: case KeyBindingAction.GoToHome:
dis.dispatch({ dis.dispatch({
action: 'view_home_page', action: Action.ViewHomePage,
}); });
Modal.closeCurrentModal("homeKeyboardShortcut"); Modal.closeCurrentModal("homeKeyboardShortcut");
handled = true; handled = true;

View file

@ -119,6 +119,10 @@ import { SummarizedNotificationState } from "../../stores/notifications/Summariz
import GenericToast from '../views/toasts/GenericToast'; import GenericToast from '../views/toasts/GenericToast';
import Views from '../../Views'; import Views from '../../Views';
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { ViewHomePagePayload } from '../../dispatcher/payloads/ViewHomePagePayload';
import { AfterLeaveRoomPayload } from '../../dispatcher/payloads/AfterLeaveRoomPayload';
import { DoAfterSyncPreparedPayload } from '../../dispatcher/payloads/DoAfterSyncPreparedPayload';
import { ViewStartChatOrReusePayload } from '../../dispatcher/payloads/ViewStartChatOrReusePayload';
// legacy export // legacy export
export { default as Views } from "../../Views"; export { default as Views } from "../../Views";
@ -541,7 +545,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// will cause a full login and sync and finally the deferred // will cause a full login and sync and finally the deferred
// action will be dispatched. // action will be dispatched.
dis.dispatch({ dis.dispatch({
action: 'do_after_sync_prepared', action: Action.DoAfterSyncPrepared,
deferred_action: payload, deferred_action: payload,
}); });
dis.dispatch({ action: 'require_registration' }); dis.dispatch({ action: 'require_registration' });
@ -632,7 +636,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
MatrixClientPeg.get().leave(payload.room_id).then(() => { MatrixClientPeg.get().leave(payload.room_id).then(() => {
modal.close(); modal.close();
if (this.state.currentRoomId === payload.room_id) { if (this.state.currentRoomId === payload.room_id) {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: Action.ViewHomePage });
} }
}, (err) => { }, (err) => {
modal.close(); modal.close();
@ -705,10 +709,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
case 'view_welcome_page': case 'view_welcome_page':
this.viewWelcome(); this.viewWelcome();
break; break;
case 'view_home_page': case Action.ViewHomePage:
this.viewHome(payload.justRegistered); this.viewHome(payload.justRegistered);
break; break;
case 'view_start_chat_or_reuse': case Action.ViewStartChatOrReuse:
this.chatCreateOrReuse(payload.user_id); this.chatCreateOrReuse(payload.user_id);
break; break;
case 'view_create_chat': case 'view_create_chat':
@ -1057,10 +1061,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// No point in making 2 DMs with welcome bot. This assumes view_set_mxid will // No point in making 2 DMs with welcome bot. This assumes view_set_mxid will
// result in a new DM with the welcome user. // result in a new DM with the welcome user.
if (userId !== this.props.config.welcomeUserId) { if (userId !== this.props.config.welcomeUserId) {
dis.dispatch({ dis.dispatch<DoAfterSyncPreparedPayload<ViewStartChatOrReusePayload>>({
action: 'do_after_sync_prepared', action: Action.DoAfterSyncPrepared,
deferred_action: { deferred_action: {
action: 'view_start_chat_or_reuse', action: Action.ViewStartChatOrReuse,
user_id: userId, user_id: userId,
}, },
}); });
@ -1162,8 +1166,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (shouldLeave) { if (shouldLeave) {
leaveRoomBehaviour(roomId); leaveRoomBehaviour(roomId);
dis.dispatch({ dis.dispatch<AfterLeaveRoomPayload>({
action: "after_leave_room", action: Action.AfterLeaveRoom,
room_id: roomId, room_id: roomId,
}); });
} }
@ -1176,7 +1180,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
MatrixClientPeg.get().forget(roomId).then(() => { MatrixClientPeg.get().forget(roomId).then(() => {
// Switch to home page if we're currently viewing the forgotten room // Switch to home page if we're currently viewing the forgotten room
if (this.state.currentRoomId === roomId) { if (this.state.currentRoomId === roomId) {
dis.dispatch({ action: "view_home_page" }); dis.dispatch({ action: Action.ViewHomePage });
} }
// We have to manually update the room list because the forgotten room will not // We have to manually update the room list because the forgotten room will not
@ -1275,7 +1279,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (welcomeUserRoom === null) { if (welcomeUserRoom === null) {
// We didn't redirect to the welcome user room, so show // We didn't redirect to the welcome user room, so show
// the homepage. // the homepage.
dis.dispatch({ action: 'view_home_page', justRegistered: true }); dis.dispatch<ViewHomePagePayload>({ action: Action.ViewHomePage, justRegistered: true });
} }
} else if (ThreepidInviteStore.instance.pickBestInvite()) { } else if (ThreepidInviteStore.instance.pickBestInvite()) {
// The user has a 3pid invite pending - show them that // The user has a 3pid invite pending - show them that
@ -1288,7 +1292,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} else { } else {
// The user has just logged in after registering, // The user has just logged in after registering,
// so show the homepage. // so show the homepage.
dis.dispatch({ action: 'view_home_page', justRegistered: true }); dis.dispatch<ViewHomePagePayload>({ action: Action.ViewHomePage, justRegistered: true });
} }
} else { } else {
this.showScreenAfterLogin(); this.showScreenAfterLogin();
@ -1353,7 +1357,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
dis.dispatch({ action: 'view_welcome_page' }); dis.dispatch({ action: 'view_welcome_page' });
} else { } else {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: Action.ViewHomePage });
} }
} }
} }
@ -1666,7 +1670,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const isLoggedOutOrGuest = !cli || cli.isGuest(); const isLoggedOutOrGuest = !cli || cli.isGuest();
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) { if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
// user is logged in and landing on an auth page which will uproot their session, redirect them home instead // user is logged in and landing on an auth page which will uproot their session, redirect them home instead
dis.dispatch({ action: "view_home_page" }); dis.dispatch({ action: Action.ViewHomePage });
return; return;
} }
@ -1714,7 +1718,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}); });
} else if (screen === 'home') { } else if (screen === 'home') {
dis.dispatch({ dis.dispatch({
action: 'view_home_page', action: Action.ViewHomePage,
}); });
} else if (screen === 'start') { } else if (screen === 'start') {
this.showScreen('home'); this.showScreen('home');
@ -1737,7 +1741,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
PlatformPeg.get().startSingleSignOn(cli, type, this.getFragmentAfterLogin()); PlatformPeg.get().startSingleSignOn(cli, type, this.getFragmentAfterLogin());
} else if (screen === 'groups') { } else if (screen === 'groups') {
if (SpaceStore.spacesEnabled) { if (SpaceStore.spacesEnabled) {
dis.dispatch({ action: "view_home_page" }); dis.dispatch({ action: Action.ViewHomePage });
return; return;
} }
dis.dispatch({ dis.dispatch({

View file

@ -47,6 +47,7 @@ import { E2EStatus } from '../../utils/ShieldUtils';
import TimelineCard from '../views/right_panel/TimelineCard'; import TimelineCard from '../views/right_panel/TimelineCard';
import { UPDATE_EVENT } from '../../stores/AsyncStore'; import { UPDATE_EVENT } from '../../stores/AsyncStore';
import { IRightPanelCard, IRightPanelCardState } from '../../stores/right-panel/RightPanelStoreIPanelState'; import { IRightPanelCard, IRightPanelCardState } from '../../stores/right-panel/RightPanelStoreIPanelState';
import { Action } from '../../dispatcher/actions';
interface IProps { interface IProps {
room?: Room; // if showing panels for a given room, this is set room?: Room; // if showing panels for a given room, this is set
@ -134,7 +135,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
// to the home page which is not obviously the correct thing to do, but I'm not sure // to the home page which is not obviously the correct thing to do, but I'm not sure
// anything else is - we could hide the close button altogether?) // anything else is - we could hide the close button altogether?)
dis.dispatch({ dis.dispatch({
action: "view_home_page", action: Action.ViewHomePage,
}); });
} else if ( } else if (
this.state.phase === RightPanelPhases.EncryptionPanel && this.state.phase === RightPanelPhases.EncryptionPanel &&

View file

@ -103,6 +103,7 @@ import { ActionPayload } from "../../dispatcher/payloads";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { JoinRoomPayload } from "../../dispatcher/payloads/JoinRoomPayload"; import { JoinRoomPayload } from "../../dispatcher/payloads/JoinRoomPayload";
import { DoAfterSyncPreparedPayload } from '../../dispatcher/payloads/DoAfterSyncPreparedPayload';
const DEBUG = false; const DEBUG = false;
let debuglog = function(msg: string) {}; let debuglog = function(msg: string) {};
@ -1273,11 +1274,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
if (this.context && this.context.isGuest()) { if (this.context && this.context.isGuest()) {
// Join this room once the user has registered and logged in // Join this room once the user has registered and logged in
// (If we failed to peek, we may not have a valid room object.) // (If we failed to peek, we may not have a valid room object.)
dis.dispatch({ dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
action: 'do_after_sync_prepared', action: Action.DoAfterSyncPrepared,
deferred_action: { deferred_action: {
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.getRoomId(), room_id: this.getRoomId(),
metricsTrigger: undefined,
}, },
}); });
dis.dispatch({ action: 'require_registration' }); dis.dispatch({ action: 'require_registration' });
@ -1568,7 +1570,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
rejecting: true, rejecting: true,
}); });
this.context.leave(this.state.roomId).then(() => { this.context.leave(this.state.roomId).then(() => {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: Action.ViewHomePage });
this.setState({ this.setState({
rejecting: false, rejecting: false,
}); });
@ -1601,7 +1603,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
await this.context.setIgnoredUsers(ignoredUsers); await this.context.setIgnoredUsers(ignoredUsers);
await this.context.leave(this.state.roomId); await this.context.leave(this.state.roomId);
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: Action.ViewHomePage });
this.setState({ this.setState({
rejecting: false, rejecting: false,
}); });

View file

@ -61,6 +61,7 @@ import MatrixClientContext from "../../contexts/MatrixClientContext";
import { SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload"; import { SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload";
import UserIdentifierCustomisations from "../../customisations/UserIdentifier"; import UserIdentifierCustomisations from "../../customisations/UserIdentifier";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload";
const CustomStatusSection = () => { const CustomStatusSection = () => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
@ -360,7 +361,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
defaultDispatcher.dispatch({ action: 'view_home_page' }); defaultDispatcher.dispatch<ViewHomePagePayload>({ action: Action.ViewHomePage });
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };

View file

@ -31,6 +31,7 @@ import SettingsStore from "../../../settings/SettingsStore";
import { UIFeature } from "../../../settings/UIFeature"; import { UIFeature } from "../../../settings/UIFeature";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { Action } from '../../../dispatcher/actions';
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB"; export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB"; export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB";
@ -75,7 +76,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
private onAction = (payload): void => { private onAction = (payload): void => {
// When view changes below us, close the room settings // When view changes below us, close the room settings
// whilst the modal is open this can only be triggered when someone hits Leave Room // whilst the modal is open this can only be triggered when someone hits Leave Room
if (payload.action === 'view_home_page') { if (payload.action === Action.ViewHomePage) {
this.props.onFinished(true); this.props.onFinished(true);
} }
}; };

View file

@ -30,6 +30,7 @@ import SettingsStore from "../../../settings/SettingsStore";
import { UIFeature } from "../../../settings/UIFeature"; import { UIFeature } from "../../../settings/UIFeature";
import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab"; import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab";
import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab"; import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
import { Action } from '../../../dispatcher/actions';
export enum SpaceSettingsTab { export enum SpaceSettingsTab {
General = "SPACE_GENERAL_TAB", General = "SPACE_GENERAL_TAB",
@ -44,8 +45,8 @@ interface IProps extends IDialogProps {
} }
const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => { const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => {
useDispatcher(defaultDispatcher, ({ action, ...params }) => { useDispatcher(defaultDispatcher, (payload) => {
if (action === "after_leave_room" && params.room_id === space.roomId) { if (payload.action === Action.AfterLeaveRoom && payload.room_id === space.roomId) {
onFinished(false); onFinished(false);
} }
}); });

View file

@ -49,6 +49,7 @@ import RoomViewStore from '../../../stores/RoomViewStore';
import WidgetUtils from '../../../utils/WidgetUtils'; import WidgetUtils from '../../../utils/WidgetUtils';
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { ActionPayload } from "../../../dispatcher/payloads"; import { ActionPayload } from "../../../dispatcher/payloads";
import { Action } from '../../../dispatcher/actions';
interface IProps { interface IProps {
app: IApp; app: IApp;
@ -447,7 +448,7 @@ export default class AppTile extends React.Component<IProps, IState> {
} }
break; break;
case "after_leave_room": case Action.AfterLeaveRoom:
if (payload.room_id === this.props.room?.roomId) { if (payload.room_id === this.props.room?.roomId) {
// call this before we get it echoed down /sync, so it doesn't hang around as long and look jarring // call this before we get it echoed down /sync, so it doesn't hang around as long and look jarring
this.onUserLeftRoom(); this.onUserLeftRoom();

View file

@ -24,13 +24,14 @@ import {
ICategory, ICategory,
CATEGORIES, CATEGORIES,
CategoryName, CategoryName,
KeyBindingConfig,
} from "../../../../../accessibility/KeyboardShortcuts"; } from "../../../../../accessibility/KeyboardShortcuts";
import SdkConfig from "../../../../../SdkConfig"; import SdkConfig from "../../../../../SdkConfig";
import { isMac, Key } from "../../../../../Keyboard"; import { isMac, Key } from "../../../../../Keyboard";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
// TODO: This should return KeyCombo but it has ctrlOrCmd instead of ctrlOrCmdKey // TODO: This should return KeyCombo but it has ctrlOrCmd instead of ctrlOrCmdKey
const getKeyboardShortcutValue = (name: string) => { const getKeyboardShortcutValue = (name: string): KeyBindingConfig => {
return getKeyboardShortcuts()[name]?.default; return getKeyboardShortcuts()[name]?.default;
}; };

View file

@ -45,6 +45,16 @@ export enum Action {
*/ */
ViewRoomDirectory = "view_room_directory", ViewRoomDirectory = "view_room_directory",
/**
* Fires when viewing room by room_alias fails to find room
*/
ViewRoomError = "view_room_error",
/**
* Navigates to app home
*/
ViewHomePage = "view_home_page",
/** /**
* Forces the theme to reload. No additional payload information required. * Forces the theme to reload. No additional payload information required.
*/ */
@ -224,4 +234,20 @@ export enum Action {
* Used to trigger auto rageshakes when configured * Used to trigger auto rageshakes when configured
*/ */
ReportKeyBackupNotEnabled = "report_key_backup_not_enabled", ReportKeyBackupNotEnabled = "report_key_backup_not_enabled",
/**
* Dispatched after leave room or space is finished
*/
AfterLeaveRoom = "after_leave_room",
/**
* Used to defer actions until after sync is complete
* LifecycleStore will emit deferredAction payload after 'MatrixActions.sync'
*/
DoAfterSyncPrepared = "do_after_sync_prepared",
/**
* Fired when clicking user name from group view
*/
ViewStartChatOrReuse = "view_start_chat_or_reuse",
} }

View file

@ -0,0 +1,26 @@
/*
Copyright 2022 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.
*/
import { Room } from "matrix-js-sdk";
import { Action } from "../actions";
import { ActionPayload } from "../payloads";
export interface AfterLeaveRoomPayload extends ActionPayload {
action: Action.AfterLeaveRoom;
// eslint-disable-next-line camelcase
room_id?: Room["roomId"];
}

View file

@ -0,0 +1,24 @@
/*
Copyright 2022 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.
*/
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
export interface DoAfterSyncPreparedPayload<T extends ActionPayload> extends Pick<ActionPayload, "action"> {
action: Action.DoAfterSyncPrepared;
// eslint-disable-next-line camelcase
deferred_action: T;
}

View file

@ -0,0 +1,27 @@
/*
Copyright 2022 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.
*/
import { MatrixError } from "matrix-js-sdk";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
export interface JoinRoomErrorPayload extends Pick<ActionPayload, "action"> {
action: Action.JoinRoomError;
roomId: string;
err?: MatrixError;
}

View file

@ -17,6 +17,7 @@ limitations under the License.
import { ActionPayload } from "../payloads"; import { ActionPayload } from "../payloads";
import { Action } from "../actions"; import { Action } from "../actions";
import { SettingLevel } from "../../settings/SettingLevel"; import { SettingLevel } from "../../settings/SettingLevel";
import { SettingValueType } from "../../settings/Settings";
export interface SettingUpdatedPayload extends ActionPayload { export interface SettingUpdatedPayload extends ActionPayload {
action: Action.SettingUpdated; action: Action.SettingUpdated;
@ -25,5 +26,5 @@ export interface SettingUpdatedPayload extends ActionPayload {
roomId: string; roomId: string;
level: SettingLevel; level: SettingLevel;
newValueAtLevel: SettingLevel; newValueAtLevel: SettingLevel;
newValue: any; newValue: SettingValueType;
} }

View file

@ -0,0 +1,25 @@
/*
Copyright 2022 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.
*/
import { Action } from "../actions";
import { ActionPayload } from "../payloads";
export interface ViewHomePagePayload extends ActionPayload {
action: Action.ViewHomePage;
// eslint-disable-next-line camelcase
context_switch?: boolean;
justRegistered?: boolean;
}

View file

@ -0,0 +1,29 @@
/*
Copyright 2022 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.
*/
import { MatrixError, Room } from "matrix-js-sdk";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
export interface ViewRoomErrorPayload extends Pick<ActionPayload, "action"> {
action: Action.ViewRoomError;
// eslint-disable-next-line camelcase
room_id: Room["roomId"];
// eslint-disable-next-line camelcase
room_alias?: string;
err?: MatrixError;
}

View file

@ -0,0 +1,26 @@
/*
Copyright 2022 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.
*/
import { User } from "matrix-js-sdk";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
export interface ViewStartChatOrReusePayload extends Pick<ActionPayload, "action"> {
action: Action.ViewStartChatOrReuse;
// eslint-disable-next-line camelcase
user_id: User["userId"];
}

View file

@ -25,6 +25,8 @@ import { _t } from "../languageHandler";
import dis from "../dispatcher/dispatcher"; import dis from "../dispatcher/dispatcher";
import { SettingLevel } from "../settings/SettingLevel"; import { SettingLevel } from "../settings/SettingLevel";
import { ActionPayload } from "../dispatcher/payloads"; import { ActionPayload } from "../dispatcher/payloads";
import { DoAfterSyncPreparedPayload } from "../dispatcher/payloads/DoAfterSyncPreparedPayload";
import { Action } from "../dispatcher/actions";
// TODO: Move this and related files to the js-sdk or something once finalized. // TODO: Move this and related files to the js-sdk or something once finalized.
@ -48,8 +50,8 @@ export class Mjolnir {
this.mjolnirWatchRef = SettingsStore.watchSetting("mjolnirRooms", null, this.onListsChanged.bind(this)); this.mjolnirWatchRef = SettingsStore.watchSetting("mjolnirRooms", null, this.onListsChanged.bind(this));
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
dis.dispatch({ dis.dispatch<DoAfterSyncPreparedPayload<ActionPayload>>({
action: 'do_after_sync_prepared', action: Action.DoAfterSyncPrepared,
deferred_action: { action: 'setup_mjolnir' }, deferred_action: { action: 'setup_mjolnir' },
}); });
} }

View file

@ -114,7 +114,14 @@ export const labGroupNames: Record<LabGroup, string> = {
[LabGroup.Developer]: _td("Developer"), [LabGroup.Developer]: _td("Developer"),
}; };
interface IBaseSetting { export type SettingValueType = boolean |
number |
string |
number[] |
string[] |
Record<string, unknown>;
export interface IBaseSetting<T extends SettingValueType = SettingValueType> {
isFeature?: false | undefined; isFeature?: false | undefined;
// Display names are strongly recommended for clarity. // Display names are strongly recommended for clarity.
@ -134,7 +141,7 @@ interface IBaseSetting {
// Required. Can be any data type. The value specified here should match // Required. Can be any data type. The value specified here should match
// the data being stored (ie: if a boolean is used, the setting should // the data being stored (ie: if a boolean is used, the setting should
// represent a boolean). // represent a boolean).
default: any; default: T;
// Optional settings controller. See SettingsController for more information. // Optional settings controller. See SettingsController for more information.
controller?: SettingController; controller?: SettingController;
@ -166,7 +173,7 @@ interface IBaseSetting {
}; };
} }
export interface IFeature extends Omit<IBaseSetting, "isFeature"> { export interface IFeature extends Omit<IBaseSetting<boolean>, "isFeature"> {
// Must be set to true for features. // Must be set to true for features.
isFeature: true; isFeature: true;
labsGroup: LabGroup; labsGroup: LabGroup;

View file

@ -18,13 +18,13 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
import { ActionPayload } from "../dispatcher/payloads";
import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
import defaultDispatcher from "../dispatcher/dispatcher"; import defaultDispatcher from "../dispatcher/dispatcher";
import { arrayHasDiff } from "../utils/arrays"; import { arrayHasDiff } from "../utils/arrays";
import { SettingLevel } from "../settings/SettingLevel"; import { SettingLevel } from "../settings/SettingLevel";
import { Action } from "../dispatcher/actions"; import { Action } from "../dispatcher/actions";
import { SettingUpdatedPayload } from "../dispatcher/payloads/SettingUpdatedPayload"; import { SettingUpdatedPayload } from "../dispatcher/payloads/SettingUpdatedPayload";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
const MAX_ROOMS = 20; // arbitrary const MAX_ROOMS = 20; // arbitrary
const AUTOJOIN_WAIT_THRESHOLD_MS = 90000; // 90s, the time we wait for an autojoined room to show up const AUTOJOIN_WAIT_THRESHOLD_MS = 90000; // 90s, the time we wait for an autojoined room to show up
@ -64,15 +64,14 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
return this.matrixClient?.getVisibleRooms().length >= 20; return this.matrixClient?.getVisibleRooms().length >= 20;
} }
protected async onAction(payload: ActionPayload) { protected async onAction(payload: SettingUpdatedPayload | ViewRoomPayload) {
if (!this.matrixClient) return; if (!this.matrixClient) return;
if (payload.action === Action.SettingUpdated) { if (payload.action === Action.SettingUpdated) {
const settingUpdatedPayload = payload as SettingUpdatedPayload; if (payload.settingName === 'breadcrumb_rooms') {
if (settingUpdatedPayload.settingName === 'breadcrumb_rooms') {
await this.updateRooms(); await this.updateRooms();
} else if (settingUpdatedPayload.settingName === 'breadcrumbs' || } else if (payload.settingName === 'breadcrumbs' ||
settingUpdatedPayload.settingName === 'feature_breadcrumbs_v2' payload.settingName === 'feature_breadcrumbs_v2'
) { ) {
await this.updateState({ enabled: SettingsStore.getValue("breadcrumbs", null) }); await this.updateState({ enabled: SettingsStore.getValue("breadcrumbs", null) });
} }

View file

@ -16,8 +16,10 @@ limitations under the License.
import { Store } from 'flux/utils'; import { Store } from 'flux/utils';
import { Action } from '../dispatcher/actions';
import dis from '../dispatcher/dispatcher'; import dis from '../dispatcher/dispatcher';
import { ActionPayload } from "../dispatcher/payloads"; import { ActionPayload } from "../dispatcher/payloads";
import { DoAfterSyncPreparedPayload } from '../dispatcher/payloads/DoAfterSyncPreparedPayload';
interface IState { interface IState {
deferredAction: any; deferredAction: any;
@ -44,9 +46,9 @@ class LifecycleStore extends Store<ActionPayload> {
this.__emitChange(); this.__emitChange();
} }
protected __onDispatch(payload: ActionPayload) { // eslint-disable-line @typescript-eslint/naming-convention protected __onDispatch(payload: ActionPayload | DoAfterSyncPreparedPayload<ActionPayload>) { // eslint-disable-line @typescript-eslint/naming-convention
switch (payload.action) { switch (payload.action) {
case 'do_after_sync_prepared': case Action.DoAfterSyncPrepared:
this.setState({ this.setState({
deferredAction: payload.deferred_action, deferredAction: payload.deferred_action,
}); });

View file

@ -42,6 +42,8 @@ import SpaceStore from "./spaces/SpaceStore";
import { isMetaSpace, MetaSpace } from "./spaces"; import { isMetaSpace, MetaSpace } from "./spaces";
import { JoinRoomPayload } from "../dispatcher/payloads/JoinRoomPayload"; import { JoinRoomPayload } from "../dispatcher/payloads/JoinRoomPayload";
import { JoinRoomReadyPayload } from "../dispatcher/payloads/JoinRoomReadyPayload"; import { JoinRoomReadyPayload } from "../dispatcher/payloads/JoinRoomReadyPayload";
import { JoinRoomErrorPayload } from "../dispatcher/payloads/JoinRoomErrorPayload";
import { ViewRoomErrorPayload } from "../dispatcher/payloads/ViewRoomErrorPayload";
const NUM_JOIN_RETRY = 5; const NUM_JOIN_RETRY = 5;
@ -122,7 +124,7 @@ class RoomViewStore extends Store<ActionPayload> {
// for these events blank out the roomId as we are no longer in the RoomView // for these events blank out the roomId as we are no longer in the RoomView
case 'view_create_group': case 'view_create_group':
case 'view_welcome_page': case 'view_welcome_page':
case 'view_home_page': case Action.ViewHomePage:
case 'view_my_groups': case 'view_my_groups':
case 'view_group': case 'view_group':
this.setState({ this.setState({
@ -132,7 +134,7 @@ class RoomViewStore extends Store<ActionPayload> {
wasContextSwitch: false, wasContextSwitch: false,
}); });
break; break;
case 'view_room_error': case Action.ViewRoomError:
this.viewRoomError(payload); this.viewRoomError(payload);
break; break;
case 'will_join': case 'will_join':
@ -306,8 +308,8 @@ class RoomViewStore extends Store<ActionPayload> {
roomId = result.room_id; roomId = result.room_id;
} catch (err) { } catch (err) {
logger.error("RVS failed to get room id for alias: ", err); logger.error("RVS failed to get room id for alias: ", err);
dis.dispatch({ dis.dispatch<ViewRoomErrorPayload>({
action: 'view_room_error', action: Action.ViewRoomError,
room_id: null, room_id: null,
room_alias: payload.room_alias, room_alias: payload.room_alias,
err, err,
@ -324,7 +326,7 @@ class RoomViewStore extends Store<ActionPayload> {
} }
} }
private viewRoomError(payload: ActionPayload) { private viewRoomError(payload: ViewRoomErrorPayload) {
this.setState({ this.setState({
roomId: payload.room_id, roomId: payload.room_id,
roomAlias: payload.room_alias, roomAlias: payload.room_alias,
@ -411,7 +413,7 @@ class RoomViewStore extends Store<ActionPayload> {
}); });
} }
private joinRoomError(payload: ActionPayload) { private joinRoomError(payload: JoinRoomErrorPayload) {
this.setState({ this.setState({
joining: false, joining: false,
joinError: payload.err, joinError: payload.err,

View file

@ -98,8 +98,6 @@ export class EchoStore extends AsyncStoreWithClient<IState> {
} }
} }
protected async onAction(payload: ActionPayload): Promise<any> { protected async onAction(payload: ActionPayload): Promise<void> {
// We have nothing to actually listen for
return Promise.resolve();
} }
} }

View file

@ -140,7 +140,6 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
} }
// We don't need this, but our contract says we do. // We don't need this, but our contract says we do.
protected async onAction(payload: ActionPayload) { protected async onAction(payload: ActionPayload): Promise<void> {
return Promise.resolve();
} }
} }

View file

@ -67,8 +67,7 @@ export default class RoomListLayoutStore extends AsyncStoreWithClient<IState> {
} }
// We don't need this function, but our contract says we do // We don't need this function, but our contract says we do
protected async onAction(payload: ActionPayload): Promise<any> { protected async onAction(payload: ActionPayload): Promise<void> {
return Promise.resolve();
} }
} }

View file

@ -24,7 +24,6 @@ import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
import defaultDispatcher from "../../dispatcher/dispatcher"; import defaultDispatcher from "../../dispatcher/dispatcher";
import { ActionPayload } from "../../dispatcher/payloads";
import RoomListStore from "../room-list/RoomListStore"; import RoomListStore from "../room-list/RoomListStore";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import DMRoomMap from "../../utils/DMRoomMap"; import DMRoomMap from "../../utils/DMRoomMap";
@ -61,6 +60,9 @@ import {
} from "./flattenSpaceHierarchy"; } from "./flattenSpaceHierarchy";
import { PosthogAnalytics } from "../../PosthogAnalytics"; import { PosthogAnalytics } from "../../PosthogAnalytics";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload";
import { SwitchSpacePayload } from "../../dispatcher/payloads/SwitchSpacePayload";
import { AfterLeaveRoomPayload } from "../../dispatcher/payloads/AfterLeaveRoomPayload";
interface IState { } interface IState { }
@ -92,7 +94,7 @@ const validOrder = (order: string): string | undefined => {
}; };
// For sorting space children using a validated `order`, `origin_server_ts`, `room_id` // For sorting space children using a validated `order`, `origin_server_ts`, `room_id`
export const getChildOrder = (order: string, ts: number, roomId: string): Array<Many<ListIteratee<any>>> => { export const getChildOrder = (order: string, ts: number, roomId: string): Array<Many<ListIteratee<unknown>>> => {
return [validOrder(order) ?? NaN, ts, roomId]; // NaN has lodash sort it at the end in asc return [validOrder(order) ?? NaN, ts, roomId]; // NaN has lodash sort it at the end in asc
}; };
@ -100,6 +102,13 @@ const getRoomFn: FetchRoomFn = (room: Room) => {
return RoomNotificationStateStore.instance.getRoomState(room); return RoomNotificationStateStore.instance.getRoomState(room);
}; };
type SpaceStoreActions =
| SettingUpdatedPayload
| ViewRoomPayload
| ViewHomePagePayload
| SwitchSpacePayload
| AfterLeaveRoomPayload;
export class SpaceStoreClass extends AsyncStoreWithClient<IState> { export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
// The spaces representing the roots of the various tree-like hierarchies // The spaces representing the roots of the various tree-like hierarchies
private rootSpaces: Room[] = []; private rootSpaces: Room[] = [];
@ -254,8 +263,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
metricsTrigger: "WebSpaceContextSwitch", metricsTrigger: "WebSpaceContextSwitch",
}); });
} else { } else {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewHomePagePayload>({
action: "view_home_page", action: Action.ViewHomePage,
context_switch: true, context_switch: true,
}); });
} }
@ -1097,7 +1106,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
this.setActiveSpace(this.enabledMetaSpaces[0] ?? this.spacePanelSpaces[0]?.roomId, contextSwitch); this.setActiveSpace(this.enabledMetaSpaces[0] ?? this.spacePanelSpaces[0]?.roomId, contextSwitch);
} }
protected async onAction(payload: ActionPayload) { protected async onAction(payload: SpaceStoreActions) {
if (!spacesEnabled || !this.matrixClient) return; if (!spacesEnabled || !this.matrixClient) return;
switch (payload.action) { switch (payload.action) {
@ -1129,14 +1138,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
break; break;
} }
case "view_home_page": case Action.ViewHomePage:
if (!payload.context_switch && this.enabledMetaSpaces.includes(MetaSpace.Home)) { if (!payload.context_switch && this.enabledMetaSpaces.includes(MetaSpace.Home)) {
this.setActiveSpace(MetaSpace.Home, false); this.setActiveSpace(MetaSpace.Home, false);
window.localStorage.setItem(getSpaceContextKey(this.activeSpace), ""); window.localStorage.setItem(getSpaceContextKey(this.activeSpace), "");
} }
break; break;
case "after_leave_room": case Action.AfterLeaveRoom:
if (!isMetaSpace(this._activeSpace) && payload.room_id === this._activeSpace) { if (!isMetaSpace(this._activeSpace) && payload.room_id === this._activeSpace) {
// User has left the current space, go to first space // User has left the current space, go to first space
this.goToFirstSpace(true); this.goToFirstSpace(true);

View file

@ -40,7 +40,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<unknown> {
return WidgetMessagingStore.internalInstance; return WidgetMessagingStore.internalInstance;
} }
protected async onAction(payload: ActionPayload): Promise<any> { protected async onAction(payload: ActionPayload): Promise<void> {
// nothing to do // nothing to do
} }

View file

@ -30,6 +30,7 @@ import { isMetaSpace } from "../stores/spaces";
import SpaceStore from "../stores/spaces/SpaceStore"; import SpaceStore from "../stores/spaces/SpaceStore";
import { Action } from "../dispatcher/actions"; import { Action } from "../dispatcher/actions";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
import { ViewHomePagePayload } from "../dispatcher/payloads/ViewHomePagePayload";
/** /**
* Approximation of a membership status for a given room. * Approximation of a membership status for a given room.
@ -194,6 +195,6 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
metricsTrigger: undefined, // other metricsTrigger: undefined, // other
}); });
} else { } else {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch<ViewHomePagePayload>({ action: Action.ViewHomePage });
} }
} }

View file

@ -43,6 +43,7 @@ import CreateSpaceFromCommunityDialog from "../components/views/dialogs/CreateSp
import SpacePreferencesDialog, { SpacePreferenceTab } from "../components/views/dialogs/SpacePreferencesDialog"; import SpacePreferencesDialog, { SpacePreferenceTab } from "../components/views/dialogs/SpacePreferencesDialog";
import PosthogTrackers from "../PosthogTrackers"; import PosthogTrackers from "../PosthogTrackers";
import { ButtonEvent } from "../components/views/elements/AccessibleButton"; import { ButtonEvent } from "../components/views/elements/AccessibleButton";
import { AfterLeaveRoomPayload } from "../dispatcher/payloads/AfterLeaveRoomPayload";
export const shouldShowSpaceSettings = (space: Room) => { export const shouldShowSpaceSettings = (space: Room) => {
const userId = space.client.getUserId(); const userId = space.client.getUserId();
@ -189,8 +190,8 @@ export const leaveSpace = (space: Room) => {
if (!leave) return; if (!leave) return;
await bulkSpaceBehaviour(space, rooms, room => leaveRoomBehaviour(room.roomId)); await bulkSpaceBehaviour(space, rooms, room => leaveRoomBehaviour(room.roomId));
dis.dispatch({ dis.dispatch<AfterLeaveRoomPayload>({
action: "after_leave_room", action: Action.AfterLeaveRoom,
room_id: space.roomId, room_id: space.roomId,
}); });
}, },

View file

@ -853,7 +853,7 @@ describe("SpaceStore", () => {
await run(); await run();
dispatcherRef = defaultDispatcher.register(payload => { dispatcherRef = defaultDispatcher.register(payload => {
if (payload.action === Action.ViewRoom || payload.action === "view_home_page") { if (payload.action === Action.ViewRoom || payload.action === Action.ViewHomePage) {
currentRoom = payload.room_id || null; currentRoom = payload.room_id || null;
} }
}); });