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

Add tabs to the right panel #12672

Merged
merged 12 commits into from
Jul 9, 2024
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"@sentry/browser": "^8.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@vector-im/compound-design-tokens": "^1.2.0",
"@vector-im/compound-web": "^5.1.2",
"@vector-im/compound-web": "^5.2.3",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-en": "^3.0.2",
Expand Down
4 changes: 2 additions & 2 deletions playwright/e2e/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const verify = async (page: Page, bob: Bot) => {
const bobsVerificationRequestPromise = waitForVerificationRequest(bob);

const roomInfo = await openRoomInfo(page);
await roomInfo.getByRole("menuitem", { name: "People" }).click();
await page.locator(".mx_RightPanelTabs").getByText("People").click();
await roomInfo.getByText("Bob").click();
await roomInfo.getByRole("button", { name: "Verify" }).click();
await roomInfo.getByRole("button", { name: "Start Verification" }).click();
Expand Down Expand Up @@ -279,7 +279,7 @@ test.describe("Cryptography", function () {

// Assert that verified icon is rendered
await page.getByRole("button", { name: "Room members" }).click();
await page.getByRole("button", { name: "Room information" }).click();
await page.locator(".mx_RightPanelTabs").getByText("Info").click();
await expect(page.locator('.mx_RoomSummaryCard_badges [data-kind="success"]')).toContainText("Encrypted");

// Take a snapshot of RoomSummaryCard with a verified E2EE icon
Expand Down
2 changes: 1 addition & 1 deletion playwright/e2e/crypto/dehydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ test.describe("Dehydration", () => {

await viewRoomSummaryByName(page, app, ROOM_NAME);

await page.getByRole("menuitem", { name: "People" }).click();
await page.locator(".mx_RightPanelTabs").getByText("People").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();

await getMemberTileByName(page, NAME).click();
Expand Down
2 changes: 1 addition & 1 deletion playwright/e2e/lazy-loading/lazy-loading.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ test.describe("Lazy Loading", () => {

async function openMemberlist(page: Page): Promise<void> {
await page.locator(".mx_LegacyRoomHeader").getByRole("button", { name: "Room info" }).click();
await page.locator(".mx_RoomSummaryCard").getByRole("menuitem", { name: "People" }).click(); // \d represents the number of the room members
await page.locator(".mx_RightPanelTabs").getByText("People").click();
}

function getMemberInMemberlist(page: Page, name: string): Locator {
Expand Down
7 changes: 3 additions & 4 deletions playwright/e2e/read-receipts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,19 +399,18 @@ class Helpers {
}

/**
* Close the threads panel. (Actually, close any right panel, but for these
* tests we only open the threads panel.)
* Close the threads panel.
*/
async closeThreadsPanel() {
await this.page.locator(".mx_RightPanel").getByLabel("Close").click();
await this.page.locator(".mx_LegacyRoomHeader").getByLabel("Threads").click();
await expect(this.page.locator(".mx_RightPanel")).not.toBeVisible();
}

/**
* Return to the list of threads, given we are viewing a single thread.
*/
async backToThreadsList() {
await this.page.locator(".mx_RightPanel").getByLabel("Threads").click();
await this.page.locator(".mx_LegacyRoomHeader").getByLabel("Threads").click();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions playwright/e2e/right-panel/right-panel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ test.describe("RightPanel", () => {
test("should handle viewing room member", async ({ page, app }) => {
await viewRoomSummaryByName(page, app, ROOM_NAME);

await page.getByRole("menuitem", { name: "People" }).click();
await page.locator(".mx_RightPanelTabs").getByText("People").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();

await getMemberTileByName(page, NAME).click();
Expand All @@ -123,7 +123,7 @@ test.describe("RightPanel", () => {
await page.getByRole("button", { name: "Room members" }).click();
await expect(page.locator(".mx_MemberList")).toBeVisible();

await page.getByRole("button", { name: "Room information" }).click();
await page.locator(".mx_RightPanelTabs").getByText("Info").click();
await checkRoomSummaryCard(page, ROOM_NAME);
});
});
Expand Down
8 changes: 3 additions & 5 deletions playwright/e2e/spaces/threads-activity-centre/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,10 @@ export class Helpers {
}

/**
* Assert that the thread panel is focused (actually the 'close' button, specifically)
* Assert that the thread tab is focused
*/
assertThreadPanelFocused() {
return expect(
this.page.locator(".mx_ThreadPanel").locator(".mx_BaseCard_header").getByLabel("Close"),
).toBeFocused();
assertThreadTabFocused() {
return expect(this.page.locator("#thread-panel-tab")).toBeFocused();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,12 @@ test.describe("Threads Activity Centre", () => {
await util.assertNoTacIndicator();
});

test("should focus the thread panel close button when clicking an item in the TAC", async ({
room1,
room2,
util,
msg,
}) => {
test("should focus the thread tab when clicking an item in the TAC", async ({ room1, room2, util, msg }) => {
await util.receiveMessages(room1, ["Msg1", msg.threadedOff("Msg1", "Resp1")]);

await util.openTac();
await util.clickRoomInTac(room1.name);

await util.assertThreadPanelFocused();
await util.assertThreadTabFocused();
});
});
MidhunSureshR marked this conversation as resolved.
Show resolved Hide resolved
t3chguy marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that the corners show some of the text from the tabs.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colour of Info should be darker here, and the weight of all the tab titles should be higher

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (see d94f70e)

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions res/css/_components.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@
@import "./views/right_panel/_BaseCard.pcss";
@import "./views/right_panel/_EncryptionInfo.pcss";
@import "./views/right_panel/_PinnedMessagesCard.pcss";
@import "./views/right_panel/_RightPanelTabs.pcss";
@import "./views/right_panel/_RoomSummaryCard.pcss";
@import "./views/right_panel/_ThreadPanel.pcss";
@import "./views/right_panel/_TimelineCard.pcss";
Expand Down
25 changes: 25 additions & 0 deletions res/css/views/right_panel/_RightPanelTabs.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright 2024 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

.mx_RightPanelTabs {
margin: 0;
height: 64px;
box-sizing: border-box;

ul {
margin-left: 16px;
}
}
2 changes: 1 addition & 1 deletion res/css/views/right_panel/_RoomSummaryCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ limitations under the License.
}

.mx_RoomSummaryCard_header {
padding: 15px 12px;
padding: 24px 12px 15px;
}

.mx_RoomSummaryCard_search {
Expand Down
1 change: 1 addition & 0 deletions res/css/views/rooms/_MemberList.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ limitations under the License.
display: flex;
flex-direction: column;
min-height: 0;
margin-top: 24px;

.mx_Spinner {
flex: 1 0 auto;
Expand Down
4 changes: 3 additions & 1 deletion src/components/structures/RightPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
import { IRightPanelCard, IRightPanelCardState } from "../../stores/right-panel/RightPanelStoreIPanelState";
import { Action } from "../../dispatcher/actions";
import { XOR } from "../../@types/common";
import { RightPanelTabs } from "../views/right_panel/RightPanelTabs";

interface BaseProps {
overwriteCard?: IRightPanelCard; // used to display a custom card and ignoring the RightPanelStore (used for UserView)
Expand Down Expand Up @@ -171,6 +172,7 @@ export default class RightPanel extends React.Component<Props, IState> {
<MemberList
roomId={roomId}
key={roomId}
hideHeaderButtons
onClose={this.onClose}
searchQuery={this.state.searchQuery}
onSearchQueryChanged={this.onSearchQueryChanged}
Expand Down Expand Up @@ -294,7 +296,6 @@ export default class RightPanel extends React.Component<Props, IState> {
card = (
<RoomSummaryCard
room={this.props.room}
onClose={this.onClose}
// whenever RightPanel is passed a room it is passed a permalinkcreator
permalinkCreator={this.props.permalinkCreator!}
onSearchChange={this.props.onSearchChange}
Expand All @@ -314,6 +315,7 @@ export default class RightPanel extends React.Component<Props, IState> {

return (
<aside className="mx_RightPanel" id="mx_RightPanel">
{phase && <RightPanelTabs phase={phase} />}
{card}
</aside>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
]);
}
} else {
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomMemberList);
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomMemberList);
}
break;
case Action.View3pidInvite:
Expand Down
15 changes: 4 additions & 11 deletions src/components/structures/ThreadPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ import { ButtonEvent } from "../views/elements/AccessibleButton";
import Spinner from "../views/elements/Spinner";
import Heading from "../views/typography/Heading";
import { clearRoomNotification } from "../../utils/notifications";
import { useDispatcher } from "../../hooks/useDispatcher";
import dis from "../../dispatcher/dispatcher";
import { Action } from "../../dispatcher/actions";

interface IProps {
roomId: string;
Expand Down Expand Up @@ -259,14 +256,6 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
}
}, [timelineSet, timelinePanel]);

useDispatcher(dis, (payload) => {
// This actually foucses the close button on the threads panel, as its the only interactive element,
// but at least it puts the user in the right area of the app.
if (payload.action === Action.FocusThreadsPanel) {
closeButonRef.current?.focus();
}
});

return (
<RoomContext.Provider
value={{
Expand All @@ -277,14 +266,18 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
}}
>
<BaseCard
hideHeaderButtons
header={
<ThreadPanelHeader
filterOption={filterOption}
setFilterOption={setFilterOption}
empty={!hasThreads}
/>
}
id="thread-panel"
className="mx_ThreadPanel"
ariaLabelledBy="thread-panel-tab"
role="tabpanel"
onClose={onClose}
withoutScrollContainer={true}
ref={card}
Expand Down
34 changes: 30 additions & 4 deletions src/components/views/right_panel/BaseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ import { CardContext } from "./context";

interface IProps {
header?: ReactNode | null;
hideHeaderButtons?: boolean;
footer?: ReactNode;
className?: string;
id?: string;
role?: "tabpanel";
ariaLabelledBy?: string;
withoutScrollContainer?: boolean;
closeLabel?: string;
onClose?(ev: ButtonEvent): void;
Expand Down Expand Up @@ -62,6 +66,10 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
onClose,
onBack,
className,
id,
ariaLabelledBy,
role,
hideHeaderButtons,
header,
footer,
withoutScrollContainer,
Expand Down Expand Up @@ -100,13 +108,31 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
children = <AutoHideScrollbar>{children}</AutoHideScrollbar>;
}

let headerButtons: React.ReactElement | undefined;
if (!hideHeaderButtons) {
headerButtons = (
<>
{backButton}
{closeButton}
</>
);
}

const shouldRenderHeader = header || !hideHeaderButtons;

return (
<CardContext.Provider value={{ isCard: true }}>
<div className={classNames("mx_BaseCard", className)} ref={ref} onKeyDown={onKeyDown}>
{header !== null && (
<div
id={id}
aria-labelledby={ariaLabelledBy}
role={role}
className={classNames("mx_BaseCard", className)}
ref={ref}
onKeyDown={onKeyDown}
>
{shouldRenderHeader && (
<div className="mx_BaseCard_header">
{backButton}
{closeButton}
{headerButtons}
<div className="mx_BaseCard_headerProp">{header}</div>
</div>
)}
Expand Down
12 changes: 6 additions & 6 deletions src/components/views/right_panel/LegacyRoomHeaderButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,27 +214,27 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons<IProps> {
const currentPhase = RightPanelStore.instance.currentCard.phase;
if (currentPhase && ROOM_INFO_PHASES.includes(currentPhase)) {
if (this.state.phase === currentPhase) {
RightPanelStore.instance.showOrHidePanel(currentPhase);
RightPanelStore.instance.showOrHidePhase(currentPhase);
} else {
RightPanelStore.instance.showOrHidePanel(currentPhase, RightPanelStore.instance.currentCard.state);
RightPanelStore.instance.showOrHidePhase(currentPhase, RightPanelStore.instance.currentCard.state);
}
} else {
// This toggles for us, if needed
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomSummary);
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
}
};

private onNotificationsClicked = (): void => {
// This toggles for us, if needed
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.NotificationPanel);
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
};

private onPinnedMessagesClicked = (): void => {
// This toggles for us, if needed
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.PinnedMessages);
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.PinnedMessages);
};
private onTimelineCardClicked = (): void => {
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.Timeline);
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.Timeline);
};

private onThreadsPanelClicked = (ev: ButtonEvent): void => {
Expand Down
Loading
Loading