Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

When pinning or unpinning messages, link to the specific message #6489

Merged
merged 11 commits into from
Sep 3, 2021
83 changes: 76 additions & 7 deletions src/TextForEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,15 @@ function textForPowerEvent(event: MatrixEvent): () => string | null {
});
}

const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void => {
defaultDispatcher.dispatch({
action: 'view_room',
event_id: messageId,
highlighted: true,
room_id: roomId,
});
};

const onPinnedMessagesClick = (): void => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
Expand All @@ -419,17 +428,77 @@ const onPinnedMessagesClick = (): void => {
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
if (!SettingsStore.getValue("feature_pinning")) return null;
const senderName = event.sender ? event.sender.name : event.getSender();
const roomId = event.getRoomId();

const pinned = event.getContent().pinned ?? [];
const previouslyPinned = event.getPrevContent().pinned ?? [];
const newlyPinned = pinned.filter(item => previouslyPinned.indexOf(item) < 0);
const newlyUnpinned = previouslyPinned.filter(item => pinned.indexOf(item) < 0);

if (newlyPinned.length === 1) {
psrpinto marked this conversation as resolved.
Show resolved Hide resolved
// A single message was pinned, include a link to that message.
if (allowJSX) {
const messageId = newlyPinned.pop();

return () => (
<span>
{ _t(
"%(senderName)s pinned <a>a message</a> to this room. See all <b>pinned messages</b>.",
{ senderName },
{
"a": (sub) =>
<a onClick={(e) => onPinnedOrUnpinnedMessageClick(messageId, roomId)}>
{ sub }
</a>,
"b": (sub) =>
<a onClick={onPinnedMessagesClick}>
{ sub }
</a>,
},
) }
</span>
);
}

return () => _t("%(senderName)s pinned a message to this room. See all pinned messages.", { senderName });
}

if (newlyUnpinned.length === 1) {
// A single message was unpinned, include a link to that message.
if (allowJSX) {
const messageId = newlyUnpinned.pop();

return () => (
<span>
{ _t(
"%(senderName)s unpinned <a>a message</a> from this room. See all <b>pinned messages</b>.",
{ senderName },
{
"a": (sub) =>
<a onClick={(e) => onPinnedOrUnpinnedMessageClick(messageId, roomId)}>
{ sub }
</a>,
"b": (sub) =>
<a onClick={onPinnedMessagesClick}>
{ sub }
</a>,
},
) }
</span>
);
}

return () => _t("%(senderName)s unpinned a message from this room. See all pinned messages.", { senderName });
}

if (allowJSX) {
return () => (
<span>
{
_t(
"%(senderName)s changed the <a>pinned messages</a> for the room.",
{ senderName },
{ "a": (sub) => <a onClick={onPinnedMessagesClick}> { sub } </a> },
)
}
{ _t(
"%(senderName)s changed the <a>pinned messages</a> for the room.",
{ senderName },
{ "a": (sub) => <a onClick={onPinnedMessagesClick}> { sub } </a> },
) }
</span>
);
}
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s",
"%(senderName)s pinned <a>a message</a> to this room. See all <b>pinned messages</b>.": "%(senderName)s pinned <a>a message</a> to this room. See all <b>pinned messages</b>.",
"%(senderName)s pinned a message to this room. See all pinned messages.": "%(senderName)s pinned a message to this room. See all pinned messages.",
"%(senderName)s unpinned <a>a message</a> from this room. See all <b>pinned messages</b>.": "%(senderName)s unpinned <a>a message</a> from this room. See all <b>pinned messages</b>.",
"%(senderName)s unpinned a message from this room. See all pinned messages.": "%(senderName)s unpinned a message from this room. See all pinned messages.",
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s changed the <a>pinned messages</a> for the room.",
"%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
Expand Down
86 changes: 86 additions & 0 deletions test/TextForEvent-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import './skinned-sdk';

import { textForEvent } from "../src/TextForEvent";
import { MatrixEvent } from "matrix-js-sdk";
import SettingsStore from "../src/settings/SettingsStore";
import { SettingLevel } from "../src/settings/SettingLevel";
import renderer from 'react-test-renderer';

function mockPinnedEvent(
pinnedMessageIds?: string[],
prevPinnedMessageIds?: string[],
): MatrixEvent {
return new MatrixEvent({
type: "m.room.pinned_events",
state_key: "",
sender: "@foo:example.com",
content: {
pinned: pinnedMessageIds,
},
prev_content: {
pinned: prevPinnedMessageIds,
},
});
}

describe('TextForEvent', () => {
describe("TextForPinnedEvent", () => {
SettingsStore.setValue("feature_pinning", null, SettingLevel.DEVICE, true);

it("mentions message when a single message was pinned, with no previously pinned messages", () => {
const event = mockPinnedEvent(['message-1']);
expect(textForEvent(event)).toBe(
"@foo:example.com pinned a message to this room. See all pinned messages.",
);

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});

it("mentions message when a single message was pinned, with multiple previously pinned messages", () => {
const event = mockPinnedEvent(['message-3'], ['message-1', 'message-2']);
expect(textForEvent(event)).toBe(
"@foo:example.com pinned a message to this room. See all pinned messages.",
);

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});

it("shows generic text when multiple messages were pinned", () => {
const event = mockPinnedEvent(['message-1', 'message-2', 'message-3'], ['message-1']);
expect(textForEvent(event)).toBe("@foo:example.com changed the pinned messages for the room.");

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});

it("mentions message when a single message was unpinned, with a single message previously pinned", () => {
const event = mockPinnedEvent([], ['message-1']);
expect(textForEvent(event)).toBe(
"@foo:example.com unpinned a message from this room. See all pinned messages.",
);

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});

it("mentions message when a single message was unpinned, with multiple previously pinned messages", () => {
const event = mockPinnedEvent(['message-2'], ['message-1', 'message-2']);
expect(textForEvent(event)).toBe(
"@foo:example.com unpinned a message from this room. See all pinned messages.",
);

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});

it("shows generic text when multiple messages were unpinned", () => {
const event = mockPinnedEvent(['message-3'], ['message-1', 'message-2', 'message-3']);
expect(textForEvent(event)).toBe("@foo:example.com changed the pinned messages for the room.");

const component = renderer.create(textForEvent(event, true));
expect(component.toJSON()).toMatchSnapshot();
});
});
});
113 changes: 113 additions & 0 deletions test/__snapshots__/TextForEvent-test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
psrpinto marked this conversation as resolved.
Show resolved Hide resolved

exports[`TextForEvent TextForPinnedEvent mentions message when a single message was pinned, with multiple previously pinned messages 1`] = `
<span>
<span>
@foo:example.com pinned
<a
onClick={[Function]}
>
a message
</a>
to this room. See all
<a
onClick={[Function]}
>
pinned messages
</a>
.
</span>
</span>
`;

exports[`TextForEvent TextForPinnedEvent mentions message when a single message was pinned, with no previously pinned messages 1`] = `
<span>
<span>
@foo:example.com pinned
<a
onClick={[Function]}
>
a message
</a>
to this room. See all
<a
onClick={[Function]}
>
pinned messages
</a>
.
</span>
</span>
`;

exports[`TextForEvent TextForPinnedEvent mentions message when a single message was unpinned, with a single message previously pinned 1`] = `
<span>
<span>
@foo:example.com unpinned
<a
onClick={[Function]}
>
a message
</a>
from this room. See all
<a
onClick={[Function]}
>
pinned messages
</a>
.
</span>
</span>
`;

exports[`TextForEvent TextForPinnedEvent mentions message when a single message was unpinned, with multiple previously pinned messages 1`] = `
<span>
<span>
@foo:example.com unpinned
<a
onClick={[Function]}
>
a message
</a>
from this room. See all
<a
onClick={[Function]}
>
pinned messages
</a>
.
</span>
</span>
`;

exports[`TextForEvent TextForPinnedEvent shows generic text when multiple messages were pinned 1`] = `
<span>
<span>
@foo:example.com changed the
<a
onClick={[Function]}
>

pinned messages

</a>
for the room.
</span>
</span>
`;

exports[`TextForEvent TextForPinnedEvent shows generic text when multiple messages were unpinned 1`] = `
<span>
<span>
@foo:example.com changed the
<a
onClick={[Function]}
>

pinned messages

</a>
for the room.
</span>
</span>
`;