Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always show back button in the right panel #29128

Merged
merged 7 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion playwright/e2e/read-receipts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,10 @@ class Helpers {
await expect(threadPanel).toBeVisible();
await threadPanel.evaluate(($panel) => {
const $button = $panel.querySelector<HTMLElement>('[data-testid="base-card-back-button"]');
const title = $panel.querySelector<HTMLElement>(".mx_BaseCard_header_title")?.textContent;
// If the Threads back button is present then click it - the
// threads button can open either threads list or thread panel
if ($button) {
if ($button && title !== "Threads") {
$button.click();
}
});
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 53 additions & 7 deletions src/stores/right-panel/RightPanelStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ import { ActiveRoomChangedPayload } from "../../dispatcher/payloads/ActiveRoomCh
import { SdkContextClass } from "../../contexts/SDKContext";
import { MatrixClientPeg } from "../../MatrixClientPeg";

/**
* @see RightPanelStore#generateHistoryForPhase
*/
function getPhasesForPhase(phase: IRightPanelCard["phase"]): RightPanelPhases[] {
switch (phase) {
case RightPanelPhases.ThreadPanel:
case RightPanelPhases.MemberList:
case RightPanelPhases.PinnedMessages:
return [RightPanelPhases.RoomSummary];
case RightPanelPhases.MemberInfo:
case RightPanelPhases.ThreePidMemberInfo:
return [RightPanelPhases.RoomSummary, RightPanelPhases.MemberList];
default:
return [];
}
}

/**
* A class for tracking the state of the right panel between layouts and
* sessions. This state includes a history for each room. Each history element
Expand Down Expand Up @@ -134,16 +151,20 @@ export default class RightPanelStore extends ReadyWatchingStore {
return { state: {}, phase: null };
}

// Setters
/**
* This function behaves as following:
* - If the same phase is sent along with a non-empty state, only the state is updated and history is retained.
* - If the provided phase is different to the current phase:
* - Existing history is thrown away.
* - New card is added along with a different history, see {@link generateHistoryForPhase}
*
* If the right panel was set, this function also shows the right panel.
*/
public setCard(card: IRightPanelCard, allowClose = true, roomId?: string): void {
const rId = roomId ?? this.viewedRoomId ?? "";
// This function behaves as following:
// Update state: if the same phase is send but with a state
// Set right panel and erase history: if a "different to the current" phase is send (with or without a state)
// If the right panel is set, this function also shows the right panel.
const redirect = this.getVerificationRedirect(card);
const targetPhase = redirect?.phase ?? card.phase;
const cardState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
const cardState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? undefined : card.state);

// Checks for wrong SetRightPanelPhase requests
if (!this.isPhaseValid(targetPhase, Boolean(rId))) return;
Expand All @@ -155,7 +176,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
this.emitAndUpdateSettings();
} else if (targetPhase !== this.currentCardForRoom(rId)?.phase || !this.byRoom[rId]) {
// Set right panel and initialize/erase history
const history = [{ phase: targetPhase, state: cardState ?? {} }];
const history = this.generateHistoryForPhase(targetPhase!, cardState ?? {});
this.byRoom[rId] = { history, isOpen: true };
this.emitAndUpdateSettings();
} else {
Expand Down Expand Up @@ -247,6 +268,31 @@ export default class RightPanelStore extends ReadyWatchingStore {
}
}

/**
* For a given phase, generates card history such that it looks
* similar to how an user typically would reach said phase in the app.
* eg: User would usually reach the memberlist via room-info panel, so
* that history is added.
*/
private generateHistoryForPhase(
phase: IRightPanelCard["phase"],
cardState?: Partial<IRightPanelCardState>,
): IRightPanelCard[] {
const card = { phase, state: cardState };
if (!this.isCardStateValid(card)) {
/**
* If the card we're adding is not valid, then we just return
* an empty history.
* This is to avoid a scenario where, for eg, you set a member info
* card with invalid card state (no member) but the member list is
* shown since the created history is valid except for the last card.
*/
return [];
}
const cards = getPhasesForPhase(phase).map((p) => ({ phase: p, state: {} }));
return [...cards, card];
}

private loadCacheFromSettings(): void {
if (this.viewedRoomId) {
const room = this.mxClient?.getRoom(this.viewedRoomId);
Expand Down
9 changes: 6 additions & 3 deletions test/unit-tests/stores/right-panel/RightPanelStore-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,14 @@ describe("RightPanelStore", () => {
expect(store.isOpenForRoom("!1:example.org")).toEqual(true);
expect(store.currentCardForRoom("!1:example.org").phase).toEqual(RightPanelPhases.RoomSummary);
});
it("overwrites history if changing the phase", async () => {
it("history is generated for certain phases", async () => {
await viewRoom("!1:example.org");
store.setCard({ phase: RightPanelPhases.RoomSummary }, true, "!1:example.org");
// Setting the memberlist card should also generate a history with room summary card
store.setCard({ phase: RightPanelPhases.MemberList }, true, "!1:example.org");
expect(store.roomPhaseHistory).toEqual([{ phase: RightPanelPhases.MemberList, state: {} }]);
expect(store.roomPhaseHistory).toEqual([
{ phase: RightPanelPhases.RoomSummary, state: {} },
{ phase: RightPanelPhases.MemberList, state: {} },
]);
});
});

Expand Down
Loading