Skip to content

Commit

Permalink
Merge pull request element-hq#43 from verji/rm/1921-HoC-part3
Browse files Browse the repository at this point in the history
Rm/1921 ho c part3
  • Loading branch information
JohnSimonsen authored Jun 3, 2024
2 parents 8ffc6c9 + a5b1838 commit 99338d8
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 72 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@
"maplibre-gl": "^2.0.0",
"matrix-encrypt-attachment": "^1.0.3",
"matrix-events-sdk": "0.0.1",
"matrix-js-sdk": "32.3.0",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-widget-api": "^1.5.0",
"memoize-one": "^6.0.0",
"minimist": "^1.2.5",
"oidc-client-ts": "^3.0.1",
"opus-recorder": "^8.0.3",
"pako": "^2.0.3",
"png-chunks-extract": "^1.0.0",
"posthog-js": "1.136.1",
"posthog-js": "1.131.4",
"proposal-temporal": "^0.9.0",
"qrcode": "1.5.3",
"re-resizable": "^6.9.0",
Expand Down
80 changes: 44 additions & 36 deletions src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -675,51 +675,59 @@ class LoggedInView extends React.Component<IProps, IState> {
const audioFeedArraysForCalls = this.state.activeCalls.map((call) => {
return <AudioFeedArrayForLegacyCall call={call} key={call.callId} />;
});

const customLoggedInViewOpts = { CustomComponent: React.Fragment };
ModuleRunner.instance.invoke(
CustomComponentLifecycle.LoggedInView,
customLoggedInViewOpts as CustomComponentOpts,
);
const customSpacePanelOpts = { CustomComponent: React.Fragment };
ModuleRunner.instance.invoke(CustomComponentLifecycle.SpacePanel, customSpacePanelOpts as CustomComponentOpts);
const customLeftPanelOpts = { CustomComponent: React.Fragment };
ModuleRunner.instance.invoke(CustomComponentLifecycle.LeftPanel, customLeftPanelOpts as CustomComponentOpts);
return (
<MatrixClientContextProvider client={this._matrixClient}>
<div
onPaste={this.onPaste}
onKeyDown={this.onReactKeyDown}
className={wrapperClasses}
aria-hidden={this.props.hideToSRUsers}
>
<ToastContainer />
<div className={bodyClasses}>
<div className="mx_LeftPanel_outerWrapper">
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
<div className="mx_LeftPanel_wrapper">
<BackdropPanel blurMultiplier={0.5} backgroundImage={this.state.backgroundImage} />
<customSpacePanelOpts.CustomComponent>
<SpacePanel />
</customSpacePanelOpts.CustomComponent>
<BackdropPanel backgroundImage={this.state.backgroundImage} />
<div
className="mx_LeftPanel_wrapper--user"
ref={this._resizeContainer}
data-collapsed={this.props.collapseLhs ? true : undefined}
>
<customLeftPanelOpts.CustomComponent>
<LeftPanel
pageType={this.props.page_type as PageTypes}
isMinimized={this.props.collapseLhs || false}
resizeNotifier={this.props.resizeNotifier}
/>
</customLeftPanelOpts.CustomComponent>
<customLoggedInViewOpts.CustomComponent>
<MatrixClientContextProvider client={this._matrixClient}>
<div
onPaste={this.onPaste}
onKeyDown={this.onReactKeyDown}
className={wrapperClasses}
aria-hidden={this.props.hideToSRUsers}
>
<ToastContainer />
<div className={bodyClasses}>
<div className="mx_LeftPanel_outerWrapper">
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
<div className="mx_LeftPanel_wrapper">
<BackdropPanel blurMultiplier={0.5} backgroundImage={this.state.backgroundImage} />
<customSpacePanelOpts.CustomComponent>
<SpacePanel />
</customSpacePanelOpts.CustomComponent>
<BackdropPanel backgroundImage={this.state.backgroundImage} />
<div
className="mx_LeftPanel_wrapper--user"
ref={this._resizeContainer}
data-collapsed={this.props.collapseLhs ? true : undefined}
>
<customLeftPanelOpts.CustomComponent>
<LeftPanel
pageType={this.props.page_type as PageTypes}
isMinimized={this.props.collapseLhs || false}
resizeNotifier={this.props.resizeNotifier}
/>
</customLeftPanelOpts.CustomComponent>
</div>
</div>
</div>
<ResizeHandle passRef={this.resizeHandler} id="lp-resizer" />
<div className="mx_RoomView_wrapper">{pageElement}</div>
</div>
<ResizeHandle passRef={this.resizeHandler} id="lp-resizer" />
<div className="mx_RoomView_wrapper">{pageElement}</div>
</div>
</div>
<PipContainer />
<NonUrgentToastContainer />
{audioFeedArraysForCalls}
</MatrixClientContextProvider>
<PipContainer />
<NonUrgentToastContainer />
{audioFeedArraysForCalls}
</MatrixClientContextProvider>
</customLoggedInViewOpts.CustomComponent>
);
}
}
Expand Down
48 changes: 31 additions & 17 deletions src/components/views/messages/ReactionsRowButtonTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ limitations under the License.

import React from "react";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import {
CustomComponentLifecycle,
CustomComponentOpts,
} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle";

import { unicodeToShortcode } from "../../../HtmlUtils";
import { _t } from "../../../languageHandler";
import { formatList } from "../../../utils/FormattingUtils";
import Tooltip from "../elements/Tooltip";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { REACTION_SHORTCODE_KEY } from "./ReactionsRow";
import { ModuleRunner } from "../../../modules/ModuleRunner";
interface IProps {
// The event we're displaying reactions for
mxEvent: MatrixEvent;
Expand Down Expand Up @@ -57,26 +62,35 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent<IProp
undefined;
}
const shortName = unicodeToShortcode(content) || customReactionName;

const customReactionButtonTooltip = { CustomComponent: React.Fragment };
ModuleRunner.instance.invoke(
CustomComponentLifecycle.ReactionsRowButtonTooltip,
customReactionButtonTooltip as CustomComponentOpts,
);

tooltipLabel = (
<div>
{_t(
"timeline|reactions|tooltip",
{
shortName,
},
{
reactors: () => {
return <div className="mx_Tooltip_title">{formatList(senders, 6)}</div>;
<customReactionButtonTooltip.CustomComponent>
<div>
{_t(
"timeline|reactions|tooltip",
{
shortName,
},
reactedWith: (sub) => {
if (!shortName) {
return null;
}
return <div className="mx_Tooltip_sub">{sub}</div>;
{
reactors: () => {
return <div className="mx_Tooltip_title">{formatList(senders, 6)}</div>;
},
reactedWith: (sub) => {
if (!shortName) {
return null;
}
return <div className="mx_Tooltip_sub">{sub}</div>;
},
},
},
)}
</div>
)}
</div>
</customReactionButtonTooltip.CustomComponent>
);
}

Expand Down
47 changes: 30 additions & 17 deletions src/components/views/rooms/LegacyRoomHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import { RoomStateEvent, ISearchResults } from "matrix-js-sdk/src/matrix";
import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { IconButton, Tooltip } from "@vector-im/compound-web";
import { ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle";
import {
CustomComponentLifecycle,
CustomComponentOpts,
} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle";

import type { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { _t } from "../../../languageHandler";
Expand Down Expand Up @@ -70,6 +74,7 @@ import { SessionDuration } from "../voip/CallDuration";
import RoomCallBanner from "../beacon/RoomCallBanner";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
import { ModuleRunner } from "../../../modules/ModuleRunner";

class DisabledWithReason {
public constructor(public readonly reason: string) {}
Expand Down Expand Up @@ -843,24 +848,32 @@ export default class RoomHeader extends React.Component<IProps, IState> {
<BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} />
) : null;

const customLegacyRoomHeaderOpts = { CustomComponent: React.Fragment };
ModuleRunner.instance.invoke(
CustomComponentLifecycle.LegacyRoomHeader,
customLegacyRoomHeaderOpts as CustomComponentOpts,
);

return (
<header className="mx_LegacyRoomHeader light-panel">
<div
className="mx_LegacyRoomHeader_wrapper"
aria-owns={this.state.rightPanelOpen ? "mx_RightPanel" : undefined}
>
<div className="mx_LegacyRoomHeader_avatar">{roomAvatar}</div>
{icon}
{name}
{searchStatus}
{topicElement}
{betaPill}
{buttons}
</div>
{!isVideoRoom && <RoomCallBanner roomId={this.props.room.roomId} />}
<RoomLiveShareWarning roomId={this.props.room.roomId} />
{this.state.featureAskToJoin && <RoomKnocksBar room={this.props.room} />}
</header>
<customLegacyRoomHeaderOpts.CustomComponent>
<header className="mx_LegacyRoomHeader light-panel">
<div
className="mx_LegacyRoomHeader_wrapper"
aria-owns={this.state.rightPanelOpen ? "mx_RightPanel" : undefined}
>
<div className="mx_LegacyRoomHeader_avatar">{roomAvatar}</div>
{icon}
{name}
{searchStatus}
{topicElement}
{betaPill}
{buttons}
</div>
{!isVideoRoom && <RoomCallBanner roomId={this.props.room.roomId} />}
<RoomLiveShareWarning roomId={this.props.room.roomId} />
{this.state.featureAskToJoin && <RoomKnocksBar room={this.props.room} />}
</header>
</customLegacyRoomHeaderOpts.CustomComponent>
);
}
}
24 changes: 24 additions & 0 deletions test/components/structures/LoggedInView-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,30 @@ describe("<LoggedInView />", () => {
mockClient.setPushRuleActions.mockReset().mockResolvedValue({});
});

describe("wrap the LoggedInView with a React.Fragment", () => {
it("should wrap the LoggedInView with a React.Fragment", () => {
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => {
if (lifecycleEvent === CustomComponentLifecycle.LoggedInView) {
(opts as CustomComponentOpts).CustomComponent = ({ children }) => {
return (
<>
<div data-testid="wrapper-header">Header</div>
<div data-testid="wrapper-LoggedInView">{children}</div>
<div data-testid="wrapper-footer">Footer</div>
</>
);
};
}
});

const { container } = getComponent();

const header = container.querySelector("[data-testid=wrapper-header]");
expect(header?.nextSibling).toBe(container.querySelector("[data-testid=wrapper-LoggedInView]"));
expect(container.children[0].tagName).toEqual("DIV");
});
});

describe("synced push rules", () => {
const pushRulesEvent = new MatrixEvent({ type: EventType.PushRules });

Expand Down
94 changes: 94 additions & 0 deletions test/components/structures/ReactionsRowButtonTooltip-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
Copyright 2024 Verji Tech AS. All rights reserved.
Unauthorized copying or distribution of this file, via any medium, is strictly prohibited.
*/

import React from "react";
import { render, screen } from "@testing-library/react";
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import {
CustomComponentLifecycle,
CustomComponentOpts,
} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle";

import ReactionsRowButtonTooltip from "../../../src/components/views/messages/ReactionsRowButtonTooltip";
import { getMockClientWithEventEmitter } from "../../test-utils";
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
import { ModuleRunner } from "../../../src/modules/ModuleRunner";

describe("ReactionsRowButtonTooltip", () => {
const content = "Hello world!";
const reactionEvents = [] as any;
const visible = true;
const roomId = "myRoomId";
const mockClient = getMockClientWithEventEmitter({
mxcUrlToHttp: jest.fn().mockReturnValue("https://not.a.real.url"),
getRoom: jest.fn(),
});
const userId = "@alice:server";
const room = new Room(roomId, mockClient, userId);

const customReactionImagesEnabled = true;

const mxEvent = {
getRoomId: jest.fn().mockReturnValue(roomId),
pushDetails: {},
_replacingEvent: null,
_localRedactionEvent: null,
_isCancelled: false,
} as unknown as MatrixEvent;

const getComp = () =>
render(
<MatrixClientContext.Provider
value={{ getRoom: jest.fn().mockReturnValue(room) } as unknown as MatrixClient}
>
<ReactionsRowButtonTooltip
mxEvent={mxEvent}
content={content}
reactionEvents={reactionEvents}
visible={visible}
customReactionImagesEnabled={customReactionImagesEnabled}
/>
</MatrixClientContext.Provider>,
);

beforeEach(() => {
jest.clearAllMocks();
});

it("should render", () => {
const { asFragment } = getComp();
screen.debug();
expect(asFragment()).toMatchSnapshot();
});

describe("wrap the ReactionsRowButtonTooltip with a React.Fragment", () => {
it("should wrap the ReactionsRowButtonTooltip with a React.Fragment", () => {
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => {
if (lifecycleEvent === CustomComponentLifecycle.ReactionsRowButtonTooltip) {
(opts as CustomComponentOpts).CustomComponent = ({ children }) => {
return (
<>
<div data-testid="wrapper-header">Header</div>
<div data-testid="wrapper-ReactionsRowButtonTooltip">{children}</div>
<div data-testid="wrapper-footer">Footer</div>
</>
);
};
}
});

getComp();
expect(screen.getByTestId("wrapper-header")).toBeDefined();
expect(screen.getByTestId("wrapper-ReactionsRowButtonTooltip")).toBeDefined();
expect(screen.getByTestId("wrapper-footer")).toBeDefined();
expect(screen.getByTestId("wrapper-header").nextSibling).toBe(
screen.getByTestId("wrapper-ReactionsRowButtonTooltip"),
);
expect(screen.getByTestId("wrapper-ReactionsRowButtonTooltip").nextSibling).toBe(
screen.getByTestId("wrapper-footer"),
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ReactionsRowButtonTooltip should render 1`] = `
<DocumentFragment>
<div />
</DocumentFragment>
`;
Loading

0 comments on commit 99338d8

Please sign in to comment.