Merge branch 'develop' into t3chguy/wat/230.1
This commit is contained in:
commit
7feb5a0b49
31 changed files with 523 additions and 155 deletions
|
@ -20,6 +20,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||
|
||||
import getEntryComponentForLoginType, {
|
||||
ContinueKind,
|
||||
CustomAuthType,
|
||||
IStageComponent,
|
||||
} from "../views/auth/InteractiveAuthEntryComponents";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
|
@ -75,11 +76,11 @@ export interface InteractiveAuthProps<T> {
|
|||
// Called when the stage changes, or the stage's phase changes. First
|
||||
// argument is the stage, second is the phase. Some stages do not have
|
||||
// phases and will be counted as 0 (numeric).
|
||||
onStagePhaseChange?(stage: AuthType | null, phase: number): void;
|
||||
onStagePhaseChange?(stage: AuthType | CustomAuthType | null, phase: number): void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
authStage?: AuthType;
|
||||
authStage?: CustomAuthType | AuthType;
|
||||
stageState?: IStageStatus;
|
||||
busy: boolean;
|
||||
errorText?: string;
|
||||
|
|
|
@ -140,7 +140,7 @@ import { cleanUpDraftsIfRequired } from "../../DraftCleaner";
|
|||
// legacy export
|
||||
export { default as Views } from "../../Views";
|
||||
|
||||
const AUTH_SCREENS = ["register", "login", "forgot_password", "start_sso", "start_cas", "welcome"];
|
||||
const AUTH_SCREENS = ["register", "mobile_register", "login", "forgot_password", "start_sso", "start_cas", "welcome"];
|
||||
|
||||
// Actions that are redirected through the onboarding process prior to being
|
||||
// re-dispatched. NOTE: some actions are non-trivial and would require
|
||||
|
@ -189,6 +189,7 @@ interface IState {
|
|||
register_session_id?: string;
|
||||
// eslint-disable-next-line camelcase
|
||||
register_id_sid?: string;
|
||||
isMobileRegistration?: boolean;
|
||||
// When showing Modal dialogs we need to set aria-hidden on the root app element
|
||||
// and disable it when there are no dialogs
|
||||
hideToSRUsers: boolean;
|
||||
|
@ -243,6 +244,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
currentUserId: null,
|
||||
|
||||
hideToSRUsers: false,
|
||||
isMobileRegistration: false,
|
||||
|
||||
syncError: null, // If the current syncing status is ERROR, the error object, otherwise null.
|
||||
resizeNotifier: new ResizeNotifier(),
|
||||
|
@ -650,6 +652,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
case "require_registration":
|
||||
startAnyRegistrationFlow(payload as any);
|
||||
break;
|
||||
case "start_mobile_registration":
|
||||
this.startRegistration(payload.params || {}, true);
|
||||
break;
|
||||
case "start_registration":
|
||||
if (Lifecycle.isSoftLogout()) {
|
||||
this.onSoftLogout();
|
||||
|
@ -946,19 +951,28 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
});
|
||||
}
|
||||
|
||||
private async startRegistration(params: { [key: string]: string }): Promise<void> {
|
||||
private async startRegistration(params: { [key: string]: string }, isMobileRegistration?: boolean): Promise<void> {
|
||||
if (!SettingsStore.getValue(UIFeature.Registration)) {
|
||||
this.showScreen("welcome");
|
||||
return;
|
||||
}
|
||||
const isMobileRegistrationAllowed =
|
||||
isMobileRegistration && SettingsStore.getValue("Registration.mobileRegistrationHelper");
|
||||
|
||||
const newState: Partial<IState> = {
|
||||
view: Views.REGISTER,
|
||||
};
|
||||
|
||||
// Only honour params if they are all present, otherwise we reset
|
||||
// HS and IS URLs when switching to registration.
|
||||
if (params.client_secret && params.session_id && params.hs_url && params.is_url && params.sid) {
|
||||
if (isMobileRegistrationAllowed && params.hs_url) {
|
||||
try {
|
||||
const config = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(params.hs_url);
|
||||
newState.serverConfig = config;
|
||||
} catch (err) {
|
||||
logger.warn("Failed to load hs_url param:", params.hs_url);
|
||||
}
|
||||
} else if (params.client_secret && params.session_id && params.hs_url && params.is_url && params.sid) {
|
||||
// Only honour params if they are all present, otherwise we reset
|
||||
// HS and IS URLs when switching to registration.
|
||||
newState.serverConfig = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
|
||||
params.hs_url,
|
||||
params.is_url,
|
||||
|
@ -978,10 +992,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
newState.register_id_sid = params.sid;
|
||||
}
|
||||
|
||||
newState.isMobileRegistration = isMobileRegistrationAllowed;
|
||||
|
||||
this.setStateForNewView(newState);
|
||||
ThemeController.isLogin = true;
|
||||
this.themeWatcher.recheck();
|
||||
this.notifyNewScreen("register");
|
||||
this.notifyNewScreen(isMobileRegistrationAllowed ? "mobile_register" : "register");
|
||||
}
|
||||
|
||||
// switch view to the given room
|
||||
|
@ -1721,6 +1737,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
params: params,
|
||||
});
|
||||
PerformanceMonitor.instance.start(PerformanceEntryNames.REGISTER);
|
||||
} else if (screen === "mobile_register") {
|
||||
dis.dispatch({
|
||||
action: "start_mobile_registration",
|
||||
params: params,
|
||||
});
|
||||
} else if (screen === "login") {
|
||||
dis.dispatch({
|
||||
action: "start_login",
|
||||
|
@ -2080,6 +2101,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
onServerConfigChange={this.onServerConfigChange}
|
||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
mobileRegister={this.state.isMobileRegistration}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -17,7 +17,6 @@ import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
|||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
|
||||
import WidgetCard from "../views/right_panel/WidgetCard";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import MemberList from "../views/rooms/MemberList";
|
||||
import UserInfo from "../views/right_panel/UserInfo";
|
||||
import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
|
||||
|
@ -220,7 +219,7 @@ export default class RightPanel extends React.Component<Props, IState> {
|
|||
break;
|
||||
|
||||
case RightPanelPhases.PinnedMessages:
|
||||
if (!!this.props.room && SettingsStore.getValue("feature_pinning")) {
|
||||
if (!!this.props.room) {
|
||||
card = (
|
||||
<PinnedMessagesCard
|
||||
room={this.props.room}
|
||||
|
|
|
@ -2408,13 +2408,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
</AuxPanel>
|
||||
);
|
||||
|
||||
const isPinningEnabled = SettingsStore.getValue<boolean>("feature_pinning");
|
||||
let pinnedMessageBanner;
|
||||
if (isPinningEnabled) {
|
||||
pinnedMessageBanner = (
|
||||
<PinnedMessageBanner room={this.state.room} permalinkCreator={this.permalinkCreator} />
|
||||
);
|
||||
}
|
||||
const pinnedMessageBanner = (
|
||||
<PinnedMessageBanner room={this.state.room} permalinkCreator={this.permalinkCreator} />
|
||||
);
|
||||
|
||||
let messageComposer;
|
||||
const showComposer =
|
||||
|
|
|
@ -53,6 +53,13 @@ const debuglog = (...args: any[]): void => {
|
|||
}
|
||||
};
|
||||
|
||||
export interface MobileRegistrationResponse {
|
||||
user_id: string;
|
||||
home_server: string;
|
||||
access_token: string;
|
||||
device_id: string;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
serverConfig: ValidatedServerConfig;
|
||||
defaultDeviceDisplayName?: string;
|
||||
|
@ -62,7 +69,7 @@ interface IProps {
|
|||
sessionId?: string;
|
||||
idSid?: string;
|
||||
fragmentAfterLogin?: string;
|
||||
|
||||
mobileRegister?: boolean;
|
||||
// Called when the user has logged in. Params:
|
||||
// - object with userId, deviceId, homeserverUrl, identityServerUrl, accessToken
|
||||
// - The user's password, if available and applicable (may be cached in memory
|
||||
|
@ -410,18 +417,33 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
debuglog("Registration: ui auth finished:", { hasEmail, hasAccessToken });
|
||||
// don’t log in if we found a session for a different user
|
||||
if (hasAccessToken && !newState.differentLoggedInUserId) {
|
||||
await this.props.onLoggedIn(
|
||||
{
|
||||
userId,
|
||||
deviceId: (response as RegisterResponse).device_id!,
|
||||
homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
|
||||
identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
|
||||
accessToken,
|
||||
},
|
||||
this.state.formVals.password!,
|
||||
);
|
||||
if (this.props.mobileRegister) {
|
||||
const mobileResponse: MobileRegistrationResponse = {
|
||||
user_id: userId,
|
||||
home_server: this.state.matrixClient.getHomeserverUrl(),
|
||||
access_token: accessToken,
|
||||
device_id: (response as RegisterResponse).device_id!,
|
||||
};
|
||||
const event = new CustomEvent<MobileRegistrationResponse>("mobileregistrationresponse", {
|
||||
detail: mobileResponse,
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
newState.busy = false;
|
||||
newState.completedNoSignin = true;
|
||||
} else {
|
||||
await this.props.onLoggedIn(
|
||||
{
|
||||
userId,
|
||||
deviceId: (response as RegisterResponse).device_id!,
|
||||
homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
|
||||
identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
|
||||
accessToken,
|
||||
},
|
||||
this.state.formVals.password!,
|
||||
);
|
||||
|
||||
this.setupPushers();
|
||||
this.setupPushers();
|
||||
}
|
||||
} else {
|
||||
newState.busy = false;
|
||||
newState.completedNoSignin = true;
|
||||
|
@ -558,7 +580,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
);
|
||||
} else if (this.state.matrixClient && this.state.flows.length) {
|
||||
let ssoSection: JSX.Element | undefined;
|
||||
if (this.state.ssoFlow) {
|
||||
if (!this.props.mobileRegister && this.state.ssoFlow) {
|
||||
let continueWithSection;
|
||||
const providers = this.state.ssoFlow.identity_providers || [];
|
||||
// when there is only a single (or 0) providers we show a wide button with `Continue with X` text
|
||||
|
@ -591,7 +613,6 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{ssoSection}
|
||||
|
@ -660,7 +681,9 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
let body;
|
||||
if (this.state.completedNoSignin) {
|
||||
let regDoneText;
|
||||
if (this.state.differentLoggedInUserId) {
|
||||
if (this.props.mobileRegister) {
|
||||
regDoneText = undefined;
|
||||
} else if (this.state.differentLoggedInUserId) {
|
||||
regDoneText = (
|
||||
<div>
|
||||
<p>
|
||||
|
@ -717,6 +740,15 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
{regDoneText}
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.mobileRegister) {
|
||||
body = (
|
||||
<Fragment>
|
||||
<h1>{_t("auth|mobile_create_account_title", { hsName: this.props.serverConfig.hsName })}</h1>
|
||||
{errorText}
|
||||
{serverDeadSection}
|
||||
{this.renderRegisterComponent()}
|
||||
</Fragment>
|
||||
);
|
||||
} else {
|
||||
body = (
|
||||
<Fragment>
|
||||
|
@ -746,7 +778,9 @@ export default class Registration extends React.Component<IProps, IState> {
|
|||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.mobileRegister) {
|
||||
return <div className="mx_MobileRegister_body">{body}</div>;
|
||||
}
|
||||
return (
|
||||
<AuthPage>
|
||||
<AuthHeader />
|
||||
|
|
|
@ -18,7 +18,6 @@ import DateSeparator from "../../views/messages/DateSeparator";
|
|||
import HistoryTile from "../../views/rooms/HistoryTile";
|
||||
import EventListSummary from "../../views/elements/EventListSummary";
|
||||
import { SeparatorKind } from "../../views/messages/TimelineSeparator";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
const groupedStateEvents = [
|
||||
EventType.RoomMember,
|
||||
|
@ -91,7 +90,7 @@ export class MainGrouper extends BaseGrouper {
|
|||
return;
|
||||
}
|
||||
|
||||
if (ev.getType() === EventType.RoomPinnedEvents && !SettingsStore.getValue("feature_pinning")) {
|
||||
if (ev.getType() === EventType.RoomPinnedEvents) {
|
||||
// If pinned messages are disabled, don't show the summary
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
|||
import { AuthType, AuthDict, IInputs, IStageStatus } from "matrix-js-sdk/src/interactive-auth";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import React, { ChangeEvent, createRef, FormEvent, Fragment } from "react";
|
||||
import { Button, Text } from "@vector-im/compound-web";
|
||||
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
|
||||
|
||||
import EmailPromptIcon from "../../../../res/img/element-icons/email-prompt.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
@ -21,6 +23,7 @@ import AccessibleButton, { AccessibleButtonKind, ButtonEvent } from "../elements
|
|||
import Field from "../elements/Field";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import CaptchaForm from "./CaptchaForm";
|
||||
import { Flex } from "../../utils/Flex";
|
||||
|
||||
/* This file contains a collection of components which are used by the
|
||||
* InteractiveAuth to prompt the user to enter the information needed
|
||||
|
@ -905,11 +908,11 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
|||
}
|
||||
}
|
||||
|
||||
export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
|
||||
private popupWindow: Window | null;
|
||||
private fallbackButton = createRef<HTMLButtonElement>();
|
||||
export class FallbackAuthEntry<T = {}> extends React.Component<IAuthEntryProps & T> {
|
||||
protected popupWindow: Window | null;
|
||||
protected fallbackButton = createRef<HTMLButtonElement>();
|
||||
|
||||
public constructor(props: IAuthEntryProps) {
|
||||
public constructor(props: IAuthEntryProps & T) {
|
||||
super(props);
|
||||
|
||||
// we have to make the user click a button, as browsers will block
|
||||
|
@ -967,6 +970,50 @@ export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export enum CustomAuthType {
|
||||
// Workaround for MAS requiring non-UIA authentication for resetting cross-signing.
|
||||
MasCrossSigningReset = "org.matrix.cross_signing_reset",
|
||||
}
|
||||
|
||||
export class MasUnlockCrossSigningAuthEntry extends FallbackAuthEntry<{
|
||||
stageParams?: {
|
||||
url?: string;
|
||||
};
|
||||
}> {
|
||||
public static LOGIN_TYPE = CustomAuthType.MasCrossSigningReset;
|
||||
|
||||
private onGoToAccountClick = (): void => {
|
||||
if (!this.props.stageParams?.url) return;
|
||||
this.popupWindow = window.open(this.props.stageParams.url, "_blank");
|
||||
};
|
||||
|
||||
private onRetryClick = (): void => {
|
||||
this.props.submitAuthDict({});
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div>
|
||||
<Text>{_t("auth|uia|mas_cross_signing_reset_description")}</Text>
|
||||
<Flex gap="var(--cpd-space-4x)">
|
||||
<Button
|
||||
Icon={PopOutIcon}
|
||||
onClick={this.onGoToAccountClick}
|
||||
autoFocus
|
||||
kind="primary"
|
||||
className="mx_Dialog_nonDialogButton"
|
||||
>
|
||||
{_t("auth|uia|mas_cross_signing_reset_cta")}
|
||||
</Button>
|
||||
<Button onClick={this.onRetryClick} kind="secondary" className="mx_Dialog_nonDialogButton">
|
||||
{_t("action|retry")}
|
||||
</Button>
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IStageComponentProps extends IAuthEntryProps {
|
||||
stageParams?: Record<string, any>;
|
||||
inputs?: IInputs;
|
||||
|
@ -983,8 +1030,10 @@ export interface IStageComponent extends React.ComponentClass<React.PropsWithRef
|
|||
focus?(): void;
|
||||
}
|
||||
|
||||
export default function getEntryComponentForLoginType(loginType: AuthType): IStageComponent {
|
||||
export default function getEntryComponentForLoginType(loginType: AuthType | CustomAuthType): IStageComponent {
|
||||
switch (loginType) {
|
||||
case CustomAuthType.MasCrossSigningReset:
|
||||
return MasUnlockCrossSigningAuthEntry;
|
||||
case AuthType.Password:
|
||||
return PasswordAuthEntry;
|
||||
case AuthType.Recaptcha:
|
||||
|
|
|
@ -26,7 +26,6 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
|
|||
import { RoomNotifState } from "../../../RoomNotifs";
|
||||
import Modal from "../../../Modal";
|
||||
import ExportDialog from "../dialogs/ExportDialog";
|
||||
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
||||
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
|
||||
import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
|
@ -261,11 +260,10 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
const pinningEnabled = useFeatureEnabled("feature_pinning");
|
||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
||||
const pinCount = usePinnedEvents(room).length;
|
||||
|
||||
let pinsOption: JSX.Element | undefined;
|
||||
if (pinningEnabled && !isVideoRoom) {
|
||||
if (!isVideoRoom) {
|
||||
pinsOption = (
|
||||
<IconizedContextMenuOption
|
||||
onClick={(ev: ButtonEvent) => {
|
||||
|
|
|
@ -21,7 +21,6 @@ import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePha
|
|||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import {
|
||||
RoomNotificationStateStore,
|
||||
UPDATE_STATUS_INDICATOR,
|
||||
|
@ -245,17 +244,16 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons<IProps> {
|
|||
|
||||
const rightPanelPhaseButtons: Map<RightPanelPhases, any> = new Map();
|
||||
|
||||
if (SettingsStore.getValue("feature_pinning")) {
|
||||
rightPanelPhaseButtons.set(
|
||||
RightPanelPhases.PinnedMessages,
|
||||
<PinnedMessagesHeaderButton
|
||||
key="pinnedMessagesButton"
|
||||
room={this.props.room}
|
||||
isHighlighted={this.isPhase(RightPanelPhases.PinnedMessages)}
|
||||
onClick={this.onPinnedMessagesClicked}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
rightPanelPhaseButtons.set(
|
||||
RightPanelPhases.PinnedMessages,
|
||||
<PinnedMessagesHeaderButton
|
||||
key="pinnedMessagesButton"
|
||||
room={this.props.room}
|
||||
isHighlighted={this.isPhase(RightPanelPhases.PinnedMessages)}
|
||||
onClick={this.onPinnedMessagesClicked}
|
||||
/>,
|
||||
);
|
||||
|
||||
rightPanelPhaseButtons.set(
|
||||
RightPanelPhases.Timeline,
|
||||
<TimelineCardHeaderButton
|
||||
|
|
|
@ -49,7 +49,6 @@ import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
|||
import { E2EStatus } from "../../../utils/ShieldUtils";
|
||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
||||
import RoomName from "../elements/RoomName";
|
||||
import ExportDialog from "../dialogs/ExportDialog";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
|
@ -73,6 +72,7 @@ import { Key } from "../../../Keyboard";
|
|||
import { useTransition } from "../../../hooks/useTransition";
|
||||
import { useIsVideoRoom } from "../../../utils/video-rooms";
|
||||
import { usePinnedEvents } from "../../../hooks/usePinnedEvents";
|
||||
import { ReleaseAnnouncement } from "../../structures/ReleaseAnnouncement.tsx";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
|
@ -314,8 +314,7 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
|||
</header>
|
||||
);
|
||||
|
||||
const pinningEnabled = useFeatureEnabled("feature_pinning");
|
||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
||||
const pinCount = usePinnedEvents(room).length;
|
||||
|
||||
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
|
||||
RoomListStore.instance.getTagsForRoom(room),
|
||||
|
@ -382,17 +381,25 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
|||
|
||||
{!isVideoRoom && (
|
||||
<>
|
||||
{pinningEnabled && (
|
||||
<MenuItem
|
||||
Icon={PinIcon}
|
||||
label={_t("right_panel|pinned_messages_button")}
|
||||
onSelect={onRoomPinsClick}
|
||||
>
|
||||
<Text as="span" size="sm">
|
||||
{pinCount}
|
||||
</Text>
|
||||
</MenuItem>
|
||||
)}
|
||||
<ReleaseAnnouncement
|
||||
feature="pinningMessageList"
|
||||
header={_t("right_panel|pinned_messages|release_announcement|title")}
|
||||
description={_t("right_panel|pinned_messages|release_announcement|description")}
|
||||
closeLabel={_t("right_panel|pinned_messages|release_announcement|close")}
|
||||
placement="top"
|
||||
>
|
||||
<div>
|
||||
<MenuItem
|
||||
Icon={PinIcon}
|
||||
label={_t("right_panel|pinned_messages_button")}
|
||||
onSelect={onRoomPinsClick}
|
||||
>
|
||||
<Text as="span" size="sm">
|
||||
{pinCount}
|
||||
</Text>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</ReleaseAnnouncement>
|
||||
<MenuItem Icon={FilesIcon} label={_t("right_panel|files_button")} onSelect={onRoomFilesClick} />
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -267,15 +267,13 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
|||
[EventType.RoomServerAcl]: _td("room_settings|permissions|m.room.server_acl"),
|
||||
[EventType.Reaction]: _td("room_settings|permissions|m.reaction"),
|
||||
[EventType.RoomRedaction]: _td("room_settings|permissions|m.room.redaction"),
|
||||
[EventType.RoomPinnedEvents]: _td("room_settings|permissions|m.room.pinned_events"),
|
||||
|
||||
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
||||
"im.vector.modular.widgets": isSpaceRoom ? null : _td("room_settings|permissions|m.widget"),
|
||||
[VoiceBroadcastInfoEventType]: _td("room_settings|permissions|io.element.voice_broadcast_info"),
|
||||
};
|
||||
|
||||
if (SettingsStore.getValue("feature_pinning")) {
|
||||
plEventsToLabels[EventType.RoomPinnedEvents] = _td("room_settings|permissions|m.room.pinned_events");
|
||||
}
|
||||
// MSC3401: Native Group VoIP signaling
|
||||
if (SettingsStore.getValue("feature_group_calls")) {
|
||||
plEventsToLabels[ElementCall.CALL_EVENT_TYPE.name] = _td("room_settings|permissions|m.call");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue