mirror of
https://github.com/element-hq/element-web
synced 2024-11-28 12:28:50 +03:00
Unlabs feature pinning (#22)
This commit is contained in:
parent
74885c942f
commit
59852773ad
18 changed files with 166 additions and 99 deletions
|
@ -561,7 +561,6 @@ const onPinnedMessagesClick = (): void => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: boolean): (() => Renderable) | null {
|
function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: boolean): (() => Renderable) | null {
|
||||||
if (!SettingsStore.getValue("feature_pinning")) return null;
|
|
||||||
const senderName = getSenderName(event);
|
const senderName = getSenderName(event);
|
||||||
const roomId = event.getRoomId()!;
|
const roomId = event.getRoomId()!;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
|
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
|
||||||
import WidgetCard from "../views/right_panel/WidgetCard";
|
import WidgetCard from "../views/right_panel/WidgetCard";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
|
||||||
import MemberList from "../views/rooms/MemberList";
|
import MemberList from "../views/rooms/MemberList";
|
||||||
import UserInfo from "../views/right_panel/UserInfo";
|
import UserInfo from "../views/right_panel/UserInfo";
|
||||||
import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
|
import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
|
||||||
|
@ -220,7 +219,7 @@ export default class RightPanel extends React.Component<Props, IState> {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.PinnedMessages:
|
case RightPanelPhases.PinnedMessages:
|
||||||
if (!!this.props.room && SettingsStore.getValue("feature_pinning")) {
|
if (!!this.props.room) {
|
||||||
card = (
|
card = (
|
||||||
<PinnedMessagesCard
|
<PinnedMessagesCard
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
|
|
|
@ -2408,13 +2408,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
</AuxPanel>
|
</AuxPanel>
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPinningEnabled = SettingsStore.getValue<boolean>("feature_pinning");
|
const pinnedMessageBanner = (
|
||||||
let pinnedMessageBanner;
|
|
||||||
if (isPinningEnabled) {
|
|
||||||
pinnedMessageBanner = (
|
|
||||||
<PinnedMessageBanner room={this.state.room} permalinkCreator={this.permalinkCreator} />
|
<PinnedMessageBanner room={this.state.room} permalinkCreator={this.permalinkCreator} />
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
let messageComposer;
|
let messageComposer;
|
||||||
const showComposer =
|
const showComposer =
|
||||||
|
|
|
@ -18,7 +18,6 @@ import DateSeparator from "../../views/messages/DateSeparator";
|
||||||
import HistoryTile from "../../views/rooms/HistoryTile";
|
import HistoryTile from "../../views/rooms/HistoryTile";
|
||||||
import EventListSummary from "../../views/elements/EventListSummary";
|
import EventListSummary from "../../views/elements/EventListSummary";
|
||||||
import { SeparatorKind } from "../../views/messages/TimelineSeparator";
|
import { SeparatorKind } from "../../views/messages/TimelineSeparator";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
|
||||||
|
|
||||||
const groupedStateEvents = [
|
const groupedStateEvents = [
|
||||||
EventType.RoomMember,
|
EventType.RoomMember,
|
||||||
|
@ -91,7 +90,7 @@ export class MainGrouper extends BaseGrouper {
|
||||||
return;
|
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
|
// If pinned messages are disabled, don't show the summary
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
|
||||||
import { RoomNotifState } from "../../../RoomNotifs";
|
import { RoomNotifState } from "../../../RoomNotifs";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
|
||||||
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
|
||||||
import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog";
|
import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog";
|
||||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
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(room).length;
|
||||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
|
||||||
|
|
||||||
let pinsOption: JSX.Element | undefined;
|
let pinsOption: JSX.Element | undefined;
|
||||||
if (pinningEnabled && !isVideoRoom) {
|
if (!isVideoRoom) {
|
||||||
pinsOption = (
|
pinsOption = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
onClick={(ev: ButtonEvent) => {
|
onClick={(ev: ButtonEvent) => {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePha
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads";
|
import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
|
||||||
import {
|
import {
|
||||||
RoomNotificationStateStore,
|
RoomNotificationStateStore,
|
||||||
UPDATE_STATUS_INDICATOR,
|
UPDATE_STATUS_INDICATOR,
|
||||||
|
@ -245,7 +244,6 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
|
|
||||||
const rightPanelPhaseButtons: Map<RightPanelPhases, any> = new Map();
|
const rightPanelPhaseButtons: Map<RightPanelPhases, any> = new Map();
|
||||||
|
|
||||||
if (SettingsStore.getValue("feature_pinning")) {
|
|
||||||
rightPanelPhaseButtons.set(
|
rightPanelPhaseButtons.set(
|
||||||
RightPanelPhases.PinnedMessages,
|
RightPanelPhases.PinnedMessages,
|
||||||
<PinnedMessagesHeaderButton
|
<PinnedMessagesHeaderButton
|
||||||
|
@ -255,7 +253,7 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
onClick={this.onPinnedMessagesClicked}
|
onClick={this.onPinnedMessagesClicked}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
rightPanelPhaseButtons.set(
|
rightPanelPhaseButtons.set(
|
||||||
RightPanelPhases.Timeline,
|
RightPanelPhases.Timeline,
|
||||||
<TimelineCardHeaderButton
|
<TimelineCardHeaderButton
|
||||||
|
|
|
@ -49,7 +49,6 @@ import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||||
import { E2EStatus } from "../../../utils/ShieldUtils";
|
import { E2EStatus } from "../../../utils/ShieldUtils";
|
||||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||||
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
|
||||||
import RoomName from "../elements/RoomName";
|
import RoomName from "../elements/RoomName";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
|
@ -314,8 +313,7 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|
||||||
const pinningEnabled = useFeatureEnabled("feature_pinning");
|
const pinCount = usePinnedEvents(room).length;
|
||||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
|
||||||
|
|
||||||
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
|
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
|
||||||
RoomListStore.instance.getTagsForRoom(room),
|
RoomListStore.instance.getTagsForRoom(room),
|
||||||
|
@ -382,7 +380,6 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
||||||
|
|
||||||
{!isVideoRoom && (
|
{!isVideoRoom && (
|
||||||
<>
|
<>
|
||||||
{pinningEnabled && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Icon={PinIcon}
|
Icon={PinIcon}
|
||||||
label={_t("right_panel|pinned_messages_button")}
|
label={_t("right_panel|pinned_messages_button")}
|
||||||
|
@ -392,7 +389,7 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
||||||
{pinCount}
|
{pinCount}
|
||||||
</Text>
|
</Text>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
|
||||||
<MenuItem Icon={FilesIcon} label={_t("right_panel|files_button")} onSelect={onRoomFilesClick} />
|
<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.RoomServerAcl]: _td("room_settings|permissions|m.room.server_acl"),
|
||||||
[EventType.Reaction]: _td("room_settings|permissions|m.reaction"),
|
[EventType.Reaction]: _td("room_settings|permissions|m.reaction"),
|
||||||
[EventType.RoomRedaction]: _td("room_settings|permissions|m.room.redaction"),
|
[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)
|
// 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"),
|
"im.vector.modular.widgets": isSpaceRoom ? null : _td("room_settings|permissions|m.widget"),
|
||||||
[VoiceBroadcastInfoEventType]: _td("room_settings|permissions|io.element.voice_broadcast_info"),
|
[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
|
// MSC3401: Native Group VoIP signaling
|
||||||
if (SettingsStore.getValue("feature_group_calls")) {
|
if (SettingsStore.getValue("feature_group_calls")) {
|
||||||
plEventsToLabels[ElementCall.CALL_EVENT_TYPE.name] = _td("room_settings|permissions|m.call");
|
plEventsToLabels[ElementCall.CALL_EVENT_TYPE.name] = _td("room_settings|permissions|m.call");
|
||||||
|
|
|
@ -1468,7 +1468,6 @@
|
||||||
"notifications": "Enable the notifications panel in the room header",
|
"notifications": "Enable the notifications panel in the room header",
|
||||||
"oidc_native_flow": "OIDC native authentication",
|
"oidc_native_flow": "OIDC native authentication",
|
||||||
"oidc_native_flow_description": "⚠ WARNING: Experimental. Use OIDC native authentication when supported by the server.",
|
"oidc_native_flow_description": "⚠ WARNING: Experimental. Use OIDC native authentication when supported by the server.",
|
||||||
"pinning": "Message Pinning",
|
|
||||||
"release_announcement": "Release announcement",
|
"release_announcement": "Release announcement",
|
||||||
"render_reaction_images": "Render custom images in reactions",
|
"render_reaction_images": "Render custom images in reactions",
|
||||||
"render_reaction_images_description": "Sometimes referred to as \"custom emojis\".",
|
"render_reaction_images_description": "Sometimes referred to as \"custom emojis\".",
|
||||||
|
|
|
@ -275,14 +275,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
supportedLevelsAreOrdered: true,
|
supportedLevelsAreOrdered: true,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
"feature_pinning": {
|
|
||||||
isFeature: true,
|
|
||||||
labsGroup: LabGroup.Messaging,
|
|
||||||
displayName: _td("labs|pinning"),
|
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
|
|
||||||
supportedLevelsAreOrdered: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
"feature_wysiwyg_composer": {
|
"feature_wysiwyg_composer": {
|
||||||
isFeature: true,
|
isFeature: true,
|
||||||
labsGroup: LabGroup.Messaging,
|
labsGroup: LabGroup.Messaging,
|
||||||
|
|
|
@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import { MatrixEvent, EventType, M_POLL_START, MatrixClient, EventTimeline, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent, EventType, M_POLL_START, MatrixClient, EventTimeline, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { isContentActionable } from "./EventUtils";
|
import { isContentActionable } from "./EventUtils";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
|
||||||
import { ReadPinsEventId } from "../components/views/right_panel/types";
|
import { ReadPinsEventId } from "../components/views/right_panel/types";
|
||||||
|
|
||||||
export default class PinningUtils {
|
export default class PinningUtils {
|
||||||
|
@ -70,7 +69,6 @@ export default class PinningUtils {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private static canPinOrUnpin(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean {
|
private static canPinOrUnpin(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean {
|
||||||
if (!SettingsStore.getValue("feature_pinning")) return false;
|
|
||||||
if (!isContentActionable(mxEvent)) return false;
|
if (!isContentActionable(mxEvent)) return false;
|
||||||
|
|
||||||
const room = matrixClient.getRoom(mxEvent.getRoomId());
|
const room = matrixClient.getRoom(mxEvent.getRoomId());
|
||||||
|
|
|
@ -65,11 +65,6 @@ describe("TextForEvent", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("TextForPinnedEvent", () => {
|
describe("TextForPinnedEvent", () => {
|
||||||
beforeAll(() => {
|
|
||||||
// enable feature_pinning setting
|
|
||||||
(SettingsStore.getValue as jest.Mock).mockImplementation((feature) => feature === "feature_pinning");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("mentions message when a single message was pinned, with no previously pinned messages", () => {
|
it("mentions message when a single message was pinned, with no previously pinned messages", () => {
|
||||||
const event = mockPinnedEvent(["message-1"]);
|
const event = mockPinnedEvent(["message-1"]);
|
||||||
const plainText = textForEvent(event, mockClient);
|
const plainText = textForEvent(event, mockClient);
|
||||||
|
|
|
@ -116,22 +116,6 @@ describe("MessageContextMenu", () => {
|
||||||
expect(screen.queryByRole("menuitem", { name: "Pin" })).toBeFalsy();
|
expect(screen.queryByRole("menuitem", { name: "Pin" })).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not show pin option when pinning feature is disabled", () => {
|
|
||||||
const eventContent = createMessageEventContent("hello");
|
|
||||||
const pinnableEvent = new MatrixEvent({
|
|
||||||
type: EventType.RoomMessage,
|
|
||||||
content: eventContent,
|
|
||||||
room_id: roomId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// disable pinning feature
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
|
||||||
|
|
||||||
createMenu(pinnableEvent, { rightClick: true }, {}, undefined, room);
|
|
||||||
|
|
||||||
expect(screen.queryByRole("menuitem", { name: "Pin" })).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows pin option when pinning feature is enabled", () => {
|
it("shows pin option when pinning feature is enabled", () => {
|
||||||
const eventContent = createMessageEventContent("hello");
|
const eventContent = createMessageEventContent("hello");
|
||||||
const pinnableEvent = new MatrixEvent({
|
const pinnableEvent = new MatrixEvent({
|
||||||
|
|
|
@ -259,8 +259,7 @@ describe("<RoomSummaryCard />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("pinning", () => {
|
describe("pinning", () => {
|
||||||
it("renders pins options when pinning feature is enabled", () => {
|
it("renders pins options", () => {
|
||||||
mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_pinning");
|
|
||||||
const { getByText } = getComponent();
|
const { getByText } = getComponent();
|
||||||
|
|
||||||
expect(getByText("Pinned messages")).toBeInTheDocument();
|
expect(getByText("Pinned messages")).toBeInTheDocument();
|
||||||
|
@ -291,9 +290,7 @@ describe("<RoomSummaryCard />", () => {
|
||||||
describe("video rooms", () => {
|
describe("video rooms", () => {
|
||||||
it("does not render irrelevant options for element video room", () => {
|
it("does not render irrelevant options for element video room", () => {
|
||||||
jest.spyOn(room, "isElementVideoRoom").mockReturnValue(true);
|
jest.spyOn(room, "isElementVideoRoom").mockReturnValue(true);
|
||||||
mocked(settingsHooks.useFeatureEnabled).mockImplementation(
|
mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_video_rooms");
|
||||||
(feature) => feature === "feature_video_rooms" || feature === "feature_pinning",
|
|
||||||
);
|
|
||||||
const { queryByText } = getComponent();
|
const { queryByText } = getComponent();
|
||||||
|
|
||||||
// options not rendered
|
// options not rendered
|
||||||
|
@ -305,10 +302,7 @@ describe("<RoomSummaryCard />", () => {
|
||||||
it("does not render irrelevant options for element call room", () => {
|
it("does not render irrelevant options for element call room", () => {
|
||||||
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
||||||
mocked(settingsHooks.useFeatureEnabled).mockImplementation(
|
mocked(settingsHooks.useFeatureEnabled).mockImplementation(
|
||||||
(feature) =>
|
(feature) => feature === "feature_element_call_video_rooms" || feature === "feature_video_rooms",
|
||||||
feature === "feature_element_call_video_rooms" ||
|
|
||||||
feature === "feature_video_rooms" ||
|
|
||||||
feature === "feature_pinning",
|
|
||||||
);
|
);
|
||||||
const { queryByText } = getComponent();
|
const { queryByText } = getComponent();
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,50 @@ exports[`<RoomSummaryCard /> has button to edit topic 1`] = `
|
||||||
data-orientation="horizontal"
|
data-orientation="horizontal"
|
||||||
role="separator"
|
role="separator"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
|
data-kind="primary"
|
||||||
|
role="menuitem"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_icon_1gwvj_44"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M6.119 2a.5.5 0 0 0-.35.857L7.85 4.9a.5.5 0 0 1 .15.357v4.487a.5.5 0 0 1-.15.356l-3.7 3.644A.5.5 0 0 0 4 14.1v1.4a.5.5 0 0 0 .5.5H11v6a1 1 0 1 0 2 0v-6h6.5a.5.5 0 0 0 .5-.5v-1.4a.5.5 0 0 0-.15-.356l-3.7-3.644a.5.5 0 0 1-.15-.356V5.257a.5.5 0 0 1 .15-.357l2.081-2.043a.5.5 0 0 0-.35-.857H6.119ZM10 4h4v5.744a2.5 2.5 0 0 0 .746 1.781L17.26 14H6.74l2.514-2.475A2.5 2.5 0 0 0 10 9.744V4Z"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 _label_1gwvj_53"
|
||||||
|
>
|
||||||
|
Pinned messages
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_nav-hint_1gwvj_60"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="8 0 8 24"
|
||||||
|
width="8"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.7 17.3a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7l3.9-3.9-3.9-3.9a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275l4.6 4.6c.1.1.17.208.213.325.041.117.062.242.062.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-4.6 4.6a.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
data-kind="primary"
|
data-kind="primary"
|
||||||
|
@ -584,6 +628,50 @@ exports[`<RoomSummaryCard /> renders the room summary 1`] = `
|
||||||
data-orientation="horizontal"
|
data-orientation="horizontal"
|
||||||
role="separator"
|
role="separator"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
|
data-kind="primary"
|
||||||
|
role="menuitem"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_icon_1gwvj_44"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M6.119 2a.5.5 0 0 0-.35.857L7.85 4.9a.5.5 0 0 1 .15.357v4.487a.5.5 0 0 1-.15.356l-3.7 3.644A.5.5 0 0 0 4 14.1v1.4a.5.5 0 0 0 .5.5H11v6a1 1 0 1 0 2 0v-6h6.5a.5.5 0 0 0 .5-.5v-1.4a.5.5 0 0 0-.15-.356l-3.7-3.644a.5.5 0 0 1-.15-.356V5.257a.5.5 0 0 1 .15-.357l2.081-2.043a.5.5 0 0 0-.35-.857H6.119ZM10 4h4v5.744a2.5 2.5 0 0 0 .746 1.781L17.26 14H6.74l2.514-2.475A2.5 2.5 0 0 0 10 9.744V4Z"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 _label_1gwvj_53"
|
||||||
|
>
|
||||||
|
Pinned messages
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_nav-hint_1gwvj_60"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="8 0 8 24"
|
||||||
|
width="8"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.7 17.3a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7l3.9-3.9-3.9-3.9a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275l4.6 4.6c.1.1.17.208.213.325.041.117.062.242.062.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-4.6 4.6a.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
data-kind="primary"
|
data-kind="primary"
|
||||||
|
@ -1009,6 +1097,50 @@ exports[`<RoomSummaryCard /> renders the room topic in the summary 1`] = `
|
||||||
data-orientation="horizontal"
|
data-orientation="horizontal"
|
||||||
role="separator"
|
role="separator"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
|
data-kind="primary"
|
||||||
|
role="menuitem"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_icon_1gwvj_44"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M6.119 2a.5.5 0 0 0-.35.857L7.85 4.9a.5.5 0 0 1 .15.357v4.487a.5.5 0 0 1-.15.356l-3.7 3.644A.5.5 0 0 0 4 14.1v1.4a.5.5 0 0 0 .5.5H11v6a1 1 0 1 0 2 0v-6h6.5a.5.5 0 0 0 .5-.5v-1.4a.5.5 0 0 0-.15-.356l-3.7-3.644a.5.5 0 0 1-.15-.356V5.257a.5.5 0 0 1 .15-.357l2.081-2.043a.5.5 0 0 0-.35-.857H6.119ZM10 4h4v5.744a2.5 2.5 0 0 0 .746 1.781L17.26 14H6.74l2.514-2.475A2.5 2.5 0 0 0 10 9.744V4Z"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 _label_1gwvj_53"
|
||||||
|
>
|
||||||
|
Pinned messages
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="_nav-hint_1gwvj_60"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="8 0 8 24"
|
||||||
|
width="8"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.7 17.3a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7l3.9-3.9-3.9-3.9a.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275l4.6 4.6c.1.1.17.208.213.325.041.117.062.242.062.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-4.6 4.6a.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
class="_item_1gwvj_17 _interactive_1gwvj_36"
|
||||||
data-kind="primary"
|
data-kind="primary"
|
||||||
|
|
|
@ -19,7 +19,6 @@ import dis from "../../../../src/dispatcher/dispatcher";
|
||||||
import { Action } from "../../../../src/dispatcher/actions";
|
import { Action } from "../../../../src/dispatcher/actions";
|
||||||
import { getForwardableEvent } from "../../../../src/events";
|
import { getForwardableEvent } from "../../../../src/events";
|
||||||
import { createRedactEventDialog } from "../../../../src/components/views/dialogs/ConfirmRedactDialog";
|
import { createRedactEventDialog } from "../../../../src/components/views/dialogs/ConfirmRedactDialog";
|
||||||
import SettingsStore from "../../../../src/settings/SettingsStore.ts";
|
|
||||||
|
|
||||||
jest.mock("../../../../src/components/views/dialogs/ConfirmRedactDialog", () => ({
|
jest.mock("../../../../src/components/views/dialogs/ConfirmRedactDialog", () => ({
|
||||||
createRedactEventDialog: jest.fn(),
|
createRedactEventDialog: jest.fn(),
|
||||||
|
@ -38,8 +37,6 @@ describe("<PinnedEventTile />", () => {
|
||||||
permalinkCreator = new RoomPermalinkCreator(room);
|
permalinkCreator = new RoomPermalinkCreator(room);
|
||||||
mockClient.getRoom = jest.fn().mockReturnValue(room);
|
mockClient.getRoom = jest.fn().mockReturnValue(room);
|
||||||
jest.spyOn(dis, "dispatch").mockReturnValue(undefined);
|
jest.spyOn(dis, "dispatch").mockReturnValue(undefined);
|
||||||
// Enable feature_pinning
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -376,8 +376,8 @@ describe("Rageshakes", () => {
|
||||||
const mockSettingsStore = mocked(SettingsStore);
|
const mockSettingsStore = mocked(SettingsStore);
|
||||||
|
|
||||||
it("should collect labs from settings store", async () => {
|
it("should collect labs from settings store", async () => {
|
||||||
const someFeatures: string[] = ["feature_video_rooms", "feature_notification_settings2", "feature_pinning"];
|
const someFeatures: string[] = ["feature_video_rooms", "feature_notification_settings2"];
|
||||||
const enabledFeatures: string[] = ["feature_video_rooms", "feature_pinning"];
|
const enabledFeatures: string[] = ["feature_video_rooms"];
|
||||||
jest.spyOn(mockSettingsStore, "getFeatureSettingNames").mockReturnValue(someFeatures);
|
jest.spyOn(mockSettingsStore, "getFeatureSettingNames").mockReturnValue(someFeatures);
|
||||||
jest.spyOn(mockSettingsStore, "getValue").mockImplementation((settingName): any => {
|
jest.spyOn(mockSettingsStore, "getValue").mockImplementation((settingName): any => {
|
||||||
return enabledFeatures.includes(settingName);
|
return enabledFeatures.includes(settingName);
|
||||||
|
|
|
@ -141,14 +141,6 @@ describe("PinningUtils", () => {
|
||||||
|
|
||||||
describe("canPin & canUnpin", () => {
|
describe("canPin & canUnpin", () => {
|
||||||
describe("canPin", () => {
|
describe("canPin", () => {
|
||||||
test("should return false if pinning is disabled", () => {
|
|
||||||
// Disable feature pinning
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
|
||||||
const event = makePinEvent();
|
|
||||||
|
|
||||||
expect(PinningUtils.canPin(matrixClient, event)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should return false if event is not actionable", () => {
|
test("should return false if event is not actionable", () => {
|
||||||
mockedIsContentActionable.mockImplementation(() => false);
|
mockedIsContentActionable.mockImplementation(() => false);
|
||||||
const event = makePinEvent();
|
const event = makePinEvent();
|
||||||
|
|
Loading…
Reference in a new issue