= (props: IProps) => {
const brand = SdkConfig.get().brand;
- let countlyFeedbackSection;
- if (hasFeedback) {
- countlyFeedbackSection =
-
-
-
{ _t("Rate %(brand)s", { brand }) }
-
-
{ _t("Tell us below how you feel about %(brand)s so far.", { brand }) }
-
{ _t("Please go into as much detail as you like, so we can track down the problem.") }
-
-
setRating(parseInt(r, 10) as Rating)}
- definitions={[
- { value: "1", label: "😠" },
- { value: "2", label: "😞" },
- { value: "3", label: "😑" },
- { value: "4", label: "😄" },
- { value: "5", label: "😍" },
- ]}
- />
-
-
- ;
- }
-
- let subheading;
- if (hasFeedback) {
- subheading = (
- { _t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand }) }
- );
+ let feedbackSection;
+ if (rageshakeUrl) {
+ feedbackSection =
+
{ _t("Comment") }
+
+
{ _t("Your platform and username will be noted to help us use your feedback as much as we can.") }
+
+
;
+ } else if (countlyEnabled) {
+ feedbackSection =
+
{ _t("Rate %(brand)s", { brand }) }
+
+
{ _t("Tell us below how you feel about %(brand)s so far.", { brand }) }
+
{ _t("Please go into as much detail as you like, so we can track down the problem.") }
+
+
setRating(parseInt(r, 10) as Rating)}
+ definitions={[
+ { value: "1", label: "😠" },
+ { value: "2", label: "😞" },
+ { value: "3", label: "😑" },
+ { value: "4", label: "😄" },
+ { value: "5", label: "😍" },
+ ]}
+ />
+
+ ;
}
let bugReports = null;
- if (SdkConfig.get().bug_report_endpoint_url) {
+ if (rageshakeUrl) {
bugReports = (
- {
+
{
_t("PRO TIP: If you start a bug, please submit debug logs " +
"to help us track down the problem.", {}, {
debugLogsLink: sub => (
@@ -121,8 +156,6 @@ const FeedbackDialog: React.FC = (props: IProps) => {
hasCancelButton={!!hasFeedback}
title={_t("Feedback")}
description={
- { subheading }
-
{ _t("Report a bug") }
{
@@ -138,10 +171,10 @@ const FeedbackDialog: React.FC = (props: IProps) => {
}
{ bugReports }
- { countlyFeedbackSection }
+ { feedbackSection }
}
button={hasFeedback ? _t("Send feedback") : _t("Go back")}
- buttonDisabled={hasFeedback && !rating}
+ buttonDisabled={hasFeedback && !rageshakeUrl && !rating}
onFinished={onFinished}
/>);
};
diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx
index c16f8553441..d5a6f8523b0 100644
--- a/src/components/views/rooms/MessageComposer.tsx
+++ b/src/components/views/rooms/MessageComposer.tsx
@@ -49,7 +49,6 @@ import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInse
import { Action } from "../../../dispatcher/actions";
import EditorModel from "../../../editor/model";
import EmojiPicker from '../emojipicker/EmojiPicker';
-import MemberStatusMessageAvatar from "../avatars/MemberStatusMessageAvatar";
import UIStore, { UI_EVENTS } from '../../../stores/UIStore';
import Modal from "../../../Modal";
import { RelationType } from 'matrix-js-sdk/src/@types/event';
@@ -61,16 +60,6 @@ import PollCreateDialog from "../elements/PollCreateDialog";
let instanceCount = 0;
const NARROW_MODE_BREAKPOINT = 500;
-interface IComposerAvatarProps {
- me: RoomMember;
-}
-
-function ComposerAvatar(props: IComposerAvatarProps) {
- return
-
-
;
-}
-
interface ISendButtonProps {
onClick: () => void;
title?: string; // defaults to something generic
@@ -567,7 +556,6 @@ export default class MessageComposer extends React.Component {
render() {
const controls = [
- this.state.me && !this.props.compact ? : null,
this.props.e2eStatus ?
:
null,
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx
index 2725eae978c..7f74d65e938 100644
--- a/src/components/views/rooms/RoomList.tsx
+++ b/src/components/views/rooms/RoomList.tsx
@@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React, { createRef, ReactComponentElement } from "react";
-import { Dispatcher } from "flux";
+import React, { ComponentType, createRef, ReactComponentElement, RefObject } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import * as fbEmitter from "fbemitter";
import { EventType } from "matrix-js-sdk/src/@types/event";
@@ -27,9 +26,8 @@ import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/Roo
import RoomViewStore from "../../../stores/RoomViewStore";
import { ITagMap } from "../../../stores/room-list/algorithms/models";
import { DefaultTagID, isCustomTag, TagID } from "../../../stores/room-list/models";
-import dis from "../../../dispatcher/dispatcher";
import defaultDispatcher from "../../../dispatcher/dispatcher";
-import RoomSublist from "./RoomSublist";
+import RoomSublist, { IAuxButtonProps } from "./RoomSublist";
import { ActionPayload } from "../../../dispatcher/payloads";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import GroupAvatar from "../avatars/GroupAvatar";
@@ -41,18 +39,28 @@ import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNo
import CustomRoomTagStore from "../../../stores/CustomRoomTagStore";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
-import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
+import IconizedContextMenu, {
+ IconizedContextMenuOption,
+ IconizedContextMenuOptionList,
+} from "../context_menus/IconizedContextMenu";
import AccessibleButton from "../elements/AccessibleButton";
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
import SpaceStore from "../../../stores/spaces/SpaceStore";
-import { ISuggestedRoom, MetaSpace, SpaceKey, UPDATE_SUGGESTED_ROOMS } from "../../../stores/spaces";
-import { showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
+import {
+ ISuggestedRoom,
+ MetaSpace,
+ SpaceKey,
+ UPDATE_SUGGESTED_ROOMS,
+ UPDATE_SELECTED_SPACE,
+} from "../../../stores/spaces";
+import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import RoomAvatar from "../avatars/RoomAvatar";
-import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
-import { JoinRule } from "matrix-js-sdk/src/@types/partials";
+import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
+import { useEventEmitterState } from "../../../hooks/useEventEmitter";
+import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
interface IProps {
@@ -95,9 +103,7 @@ const ALWAYS_VISIBLE_TAGS: TagID[] = [
interface ITagAesthetics {
sectionLabel: string;
sectionLabelRaw?: string;
- addRoomLabel?: string;
- onAddRoom?: (dispatcher?: Dispatcher) => void;
- addRoomContextMenu?: (onFinished: () => void) => React.ReactNode;
+ AuxButtonComponent?: ComponentType;
isInvite: boolean;
defaultHidden: boolean;
}
@@ -107,6 +113,194 @@ interface ITagAestheticsMap {
[tagId: TagID]: ITagAesthetics;
}
+const auxButtonContextMenuPosition = (handle: RefObject) => {
+ const rect = handle.current.getBoundingClientRect();
+ return {
+ chevronFace: ChevronFace.None,
+ left: rect.left - 7,
+ top: rect.top + rect.height,
+ };
+};
+
+const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonProps) => {
+ const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
+ const activeSpace = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
+ return SpaceStore.instance.activeSpaceRoom;
+ });
+
+ const showCreateRooms = shouldShowComponent(UIComponent.CreateRooms);
+ const showInviteUsers = shouldShowComponent(UIComponent.InviteUsers);
+
+ if (activeSpace && (showCreateRooms || showInviteUsers)) {
+ let contextMenu: JSX.Element;
+ if (menuDisplayed) {
+ const canInvite = shouldShowSpaceInvite(activeSpace);
+
+ contextMenu =
+
+ { showCreateRooms && {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ defaultDispatcher.dispatch({ action: "view_create_chat" });
+ }}
+ /> }
+ { showInviteUsers && {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ showSpaceInvite(activeSpace);
+ }}
+ disabled={!canInvite}
+ tooltip={canInvite ? undefined
+ : _t("You do not have permissions to invite people to this space")}
+ /> }
+
+ ;
+ }
+
+ return <>
+
+
+ { contextMenu }
+ >;
+ } else if (!activeSpace && showCreateRooms) {
+ return dispatcher.dispatch({ action: 'view_create_chat' })}
+ className="mx_RoomSublist_auxButton"
+ tooltipClassName="mx_RoomSublist_addRoomTooltip"
+ aria-label={_t("Start chat")}
+ title={_t("Start chat")}
+ />;
+ }
+};
+
+const UntaggedAuxButton = ({ tabIndex }: IAuxButtonProps) => {
+ const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
+ const activeSpace = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
+ return SpaceStore.instance.activeSpaceRoom;
+ });
+
+ const showCreateRoom = shouldShowComponent(UIComponent.CreateRooms);
+
+ let contextMenuContent: JSX.Element;
+ if (menuDisplayed && activeSpace) {
+ const canAddRooms = activeSpace.currentState.maySendStateEvent(EventType.SpaceChild,
+ MatrixClientPeg.get().getUserId());
+
+ contextMenuContent =
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ defaultDispatcher.dispatch({
+ action: "view_room",
+ room_id: activeSpace.roomId,
+ });
+ }}
+ />
+ {
+ showCreateRoom
+ ? (<>
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ showCreateNewRoom(activeSpace);
+ }}
+ disabled={!canAddRooms}
+ tooltip={canAddRooms ? undefined
+ : _t("You do not have permissions to create new rooms in this space")}
+ />
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ showAddExistingRooms(activeSpace);
+ }}
+ disabled={!canAddRooms}
+ tooltip={canAddRooms ? undefined
+ : _t("You do not have permissions to add rooms to this space")}
+ />
+ >)
+ : null
+ }
+ ;
+ } else if (menuDisplayed) {
+ contextMenuContent =
+ { showCreateRoom && {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ defaultDispatcher.dispatch({ action: "view_create_room" });
+ }}
+ /> }
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ closeMenu();
+ defaultDispatcher.fire(Action.ViewRoomDirectory);
+ }}
+ />
+ ;
+ }
+
+ let contextMenu: JSX.Element;
+ if (menuDisplayed) {
+ contextMenu =
+ { contextMenuContent }
+ ;
+ }
+
+ return <>
+
+
+ { contextMenu }
+ >;
+};
+
const TAG_AESTHETICS: ITagAestheticsMap = {
[DefaultTagID.Invite]: {
sectionLabel: _td("Invites"),
@@ -122,93 +316,13 @@ const TAG_AESTHETICS: ITagAestheticsMap = {
sectionLabel: _td("People"),
isInvite: false,
defaultHidden: false,
- addRoomLabel: _td("Start chat"),
- onAddRoom: (dispatcher?: Dispatcher) => {
- (dispatcher || defaultDispatcher).dispatch({ action: 'view_create_chat' });
- },
+ AuxButtonComponent: DmAuxButton,
},
[DefaultTagID.Untagged]: {
sectionLabel: _td("Rooms"),
isInvite: false,
defaultHidden: false,
- addRoomLabel: _td("Add room"),
- addRoomContextMenu: (onFinished: () => void) => {
- if (SpaceStore.instance.activeSpaceRoom) {
- const userId = MatrixClientPeg.get().getUserId();
- const space = SpaceStore.instance.activeSpaceRoom;
- const canAddRooms = space.currentState.maySendStateEvent(EventType.SpaceChild, userId);
-
- return
- {
- shouldShowComponent(UIComponent.CreateRooms)
- ? (<>
- {
- e.preventDefault();
- e.stopPropagation();
- onFinished();
- showCreateNewRoom(space);
- }}
- disabled={!canAddRooms}
- tooltip={canAddRooms ? undefined
- : _t("You do not have permissions to create new rooms in this space")}
- />
- {
- e.preventDefault();
- e.stopPropagation();
- onFinished();
- showAddExistingRooms(space);
- }}
- disabled={!canAddRooms}
- tooltip={canAddRooms ? undefined
- : _t("You do not have permissions to add rooms to this space")}
- />
- >)
- : null
- }
- {
- e.preventDefault();
- e.stopPropagation();
- onFinished();
- defaultDispatcher.fire(Action.ViewRoomDirectory);
- }}
- />
- ;
- }
-
- return
- {
- e.preventDefault();
- e.stopPropagation();
- onFinished();
- defaultDispatcher.dispatch({ action: "view_create_room" });
- }}
- />
- {
- e.preventDefault();
- e.stopPropagation();
- onFinished();
- defaultDispatcher.fire(Action.ViewRoomDirectory);
- }}
- />
- ;
- },
+ AuxButtonComponent: UntaggedAuxButton,
},
[DefaultTagID.LowPriority]: {
sectionLabel: _td("Low priority"),
@@ -296,7 +410,7 @@ export default class RoomList extends React.PureComponent {
const currentRoomId = RoomViewStore.getRoomId();
const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread);
if (room) {
- dis.dispatch({
+ defaultDispatcher.dispatch({
action: Action.ViewRoom,
room_id: room.roomId,
show_room_tile: true, // to make sure the room gets scrolled into view
@@ -375,17 +489,19 @@ export default class RoomList extends React.PureComponent {
private onStartChat = () => {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
- dis.dispatch({ action: "view_create_chat", initialText });
+ defaultDispatcher.dispatch({ action: "view_create_chat", initialText });
};
private onExplore = () => {
- const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
- dis.dispatch({ action: Action.ViewRoomDirectory, initialText });
- };
-
- private onSpaceInviteClick = () => {
- const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
- showSpaceInvite(this.context.getRoom(this.props.activeSpace), initialText);
+ if (this.props.activeSpace[0] === "!") {
+ defaultDispatcher.dispatch({
+ action: "view_room",
+ room_id: SpaceStore.instance.activeSpace,
+ });
+ } else {
+ const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
+ defaultDispatcher.dispatch({ action: Action.ViewRoomDirectory, initialText });
+ }
};
private renderSuggestedRooms(): ReactComponentElement[] {
@@ -508,9 +624,7 @@ export default class RoomList extends React.PureComponent {
forRooms={true}
startAsHidden={aesthetics.defaultHidden}
label={aesthetics.sectionLabelRaw ? aesthetics.sectionLabelRaw : _t(aesthetics.sectionLabel)}
- onAddRoom={aesthetics.onAddRoom}
- addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel}
- addRoomContextMenu={aesthetics.addRoomContextMenu}
+ AuxButtonComponent={aesthetics.AuxButtonComponent}
isMinimized={this.props.isMinimized}
showSkeleton={showSkeleton}
extraTiles={extraTiles}
@@ -528,10 +642,6 @@ export default class RoomList extends React.PureComponent {
}
public render() {
- const cli = MatrixClientPeg.get();
- const userId = cli.getUserId();
- const activeSpace = this.props.activeSpace[0] === "!" ? cli.getRoom(this.props.activeSpace) : null;
-
let explorePrompt: JSX.Element;
if (!this.props.isMinimized) {
if (this.state.isNameFiltering) {
@@ -549,58 +659,9 @@ export default class RoomList extends React.PureComponent {
kind="link"
onClick={this.onExplore}
>
- { activeSpace ? _t("Explore rooms") : _t("Explore all public rooms") }
+ { this.props.activeSpace[0] === "!" ? _t("Explore rooms") : _t("Explore all public rooms") }