Skip to content
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
2 changes: 1 addition & 1 deletion playwright/e2e/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const startDMWithBob = async (page: Page, bob: Bot) => {
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
await page.getByRole("menuitem", { name: "Start chat" }).click();
await page.getByTestId("invite-dialog-input").fill(bob.credentials.userId);
await page.locator(".mx_InviteDialog_tile_nameStack_name").getByText("Bob").click();
await page.getByRole("option", { name: bob.credentials.displayName }).click();
await expect(
page.locator(".mx_InviteDialog_userTile_pill .mx_InviteDialog_userTile_name").getByText("Bob"),
).toBeVisible();
Expand Down
12 changes: 4 additions & 8 deletions playwright/e2e/invite/invite-dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,9 @@ test.describe("Invite dialog", function () {
await expect(other.locator(".mx_InviteDialog_identityServer")).toBeVisible();

// Assert that the bot id is rendered properly
await expect(
other.locator(".mx_InviteDialog_tile_nameStack_userId").getByText(bot.credentials.userId),
).toBeVisible();
await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials.userId)).toBeVisible();

await other.locator(".mx_InviteDialog_tile_nameStack_name").getByText(botName).click();
await other.getByRole("option", { name: botName }).click();

await expect(
other.locator(".mx_InviteDialog_userTile_pill .mx_InviteDialog_userTile_name").getByText(botName),
Expand Down Expand Up @@ -94,10 +92,8 @@ test.describe("Invite dialog", function () {

await other.getByTestId("invite-dialog-input").fill(bot.credentials.userId);

await expect(
other.locator(".mx_InviteDialog_tile_nameStack").getByText(bot.credentials.userId),
).toBeVisible();
await other.locator(".mx_InviteDialog_tile_nameStack").getByText(botName).click();
await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials.userId)).toBeVisible();
await other.getByRole("option", { name: botName }).click();

await expect(
other.locator(".mx_InviteDialog_userTile_pill .mx_InviteDialog_userTile_name").getByText(botName),
Expand Down
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.
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.
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion res/css/_common.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ legend {
.mx_AccessibleButton,
.mx_IdentityServerPicker button,
.mx_AccessSecretStorageDialog button,
.mx_InviteDialog_section button,
[class|="maplibregl"]
),
.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton, .mx_AccessibleButton),
Expand Down Expand Up @@ -643,7 +644,8 @@ legend {
.mx_ThemeChoicePanel_CustomTheme button,
.mx_UnpinAllDialog button,
.mx_ShareDialog button,
.mx_EncryptionUserSettingsTab button
.mx_EncryptionUserSettingsTab button,
.mx_InviteDialog_section button
):focus,
.mx_Dialog input[type="submit"]:focus,
.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton, .mx_AccessibleButton):focus,
Expand Down
69 changes: 5 additions & 64 deletions res/css/views/dialogs/_InviteDialog.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,6 @@ Please see LICENSE files in the repository root for full details.
.mx_InviteDialog_section {
padding-bottom: $spacing-4;

h3 {
font-size: $font-12px;
color: $muted-fg-color;
font-weight: bold;
text-transform: uppercase;
}

> p {
margin: 0;
}

> span {
color: $primary-content;
}

.mx_InviteDialog_section_showMore {
margin: 7px 18px;
display: block;
Expand Down Expand Up @@ -194,10 +179,13 @@ Please see LICENSE files in the repository root for full details.
.mx_InviteDialog_userSections {
flex-grow: 1;
padding-inline-end: 0;
display: flex;
flex-direction: column;
margin-top: var(--cpd-space-3x);
gap: var(--cpd-space-3x);

.mx_InviteDialog_section {
padding-bottom: 0;
margin-top: $spacing-12;
}
}
}
Expand Down Expand Up @@ -249,7 +237,6 @@ Please see LICENSE files in the repository root for full details.
}

.mx_InviteDialog_userSections {
margin-top: $spacing-4;
overflow-y: auto;
padding: 0 45px $spacing-4 0;
}
Expand Down Expand Up @@ -325,48 +312,6 @@ Please see LICENSE files in the repository root for full details.
gap: $spacing-8 $spacing-12;
align-items: center;

&.mx_InviteDialog_tile--room {
/* mx_InviteDialog_tile_avatarStack, mx_InviteDialog_tile_nameStack, time */
grid-template-columns: min-content auto auto;
padding: $spacing-4 $spacing-8;

&:hover {
background-color: $header-panel-bg-color;
border-radius: 4px;
}

.mx_InviteDialog_tile--room_selected {
border-radius: 36px;
background-color: var(--cpd-color-bg-success-subtle);

&::before {
content: "";
width: 24px;
height: 24px;
grid-column: 1;
grid-row: 1;
mask-image: url("@vector-im/compound-design-tokens/icons/check.svg");
mask-size: 100%;
mask-repeat: no-repeat;
position: absolute;
top: 6px; /* 50% */
left: 6px; /* 50% */
background-color: $primary-content;
}
}

.mx_InviteDialog_tile--room_time {
margin-inline-start: auto;
width: max-content;
font-size: $font-12px;
color: $muted-fg-color;
}

.mx_InviteDialog_tile--room_highlight {
font-weight: 900;
}
}

&.mx_InviteDialog_tile--inviterError {
grid-template-columns: max-content auto; /* max-content = avatar width */
margin-bottom: $spacing-24;
Expand All @@ -388,15 +333,11 @@ Please see LICENSE files in the repository root for full details.
vertical-align: middle;
}

.mx_InviteDialog_tile_avatarStack,
.mx_InviteDialog_tile--room_selected {
.mx_InviteDialog_tile_avatarStack {
width: 36px;
height: 36px;
display: inline-block;
position: relative;
}

.mx_InviteDialog_tile_avatarStack {
grid-row-start: 1;
grid-column-start: 1;

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/beacon/BeaconListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import { type Beacon, BeaconEvent, LocationAssetType } from "matrix-js-sdk/src/m

import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { humanizeTime } from "../../../utils/humanize";
import { preventDefaultWrapper } from "../../../utils/NativeEventUtils";
import { _t } from "../../../languageHandler";
import MemberAvatar from "../avatars/MemberAvatar";
import BeaconStatus from "./BeaconStatus";
import { BeaconDisplayStatus } from "./displayStatus";
import StyledLiveBeaconIcon from "./StyledLiveBeaconIcon";
import ShareLatestLocation from "./ShareLatestLocation";
import { humanizeTime } from "../../../shared-components/utils/humanize";

interface Props {
beacon: Beacon;
Expand Down
103 changes: 23 additions & 80 deletions src/components/views/dialogs/InviteDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { getDefaultIdentityServerUrl, setToDefaultIdentityServer } from "../../.
import { buildActivityScores, buildMemberScores, compareMembers } from "../../../utils/SortMembers";
import { abbreviateUrl } from "../../../utils/UrlUtils";
import IdentityAuthClient from "../../../IdentityAuthClient";
import { humanizeTime } from "../../../utils/humanize";
import { type IInviteResult, inviteMultipleToRoom, showAnyInviteErrors } from "../../../RoomInvite";
import { Action } from "../../../dispatcher/actions";
import { DefaultTagID } from "../../../stores/room-list/models";
Expand Down Expand Up @@ -65,6 +64,8 @@ import AskInviteAnywayDialog, { type UnknownProfiles } from "./AskInviteAnywayDi
import { SdkContextClass } from "../../../contexts/SDKContext";
import { type UserProfilesStore } from "../../../stores/UserProfilesStore";
import InviteProgressBody from "./InviteProgressBody.tsx";
import { RichList } from "../../../shared-components/rich-list/RichList";
import { RichItem } from "../../../shared-components/rich-list/RichItem";

// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */
Expand Down Expand Up @@ -163,7 +164,6 @@ interface IDMRoomTileProps {
member: Member;
lastActiveTs?: number;
onToggle(member: Member): void;
highlightWord: string;
isSelected: boolean;
}

Expand All @@ -176,54 +176,8 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
this.props.onToggle(this.props.member);
};

private highlightName(str: string): ReactNode {
if (!this.props.highlightWord) return str;

// We convert things to lowercase for index searching, but pull substrings from
// the submitted text to preserve case. Note: we don't need to htmlEntities the
// string because React will safely encode the text for us.
const lowerStr = str.toLowerCase();
const filterStr = this.props.highlightWord.toLowerCase();

const result: JSX.Element[] = [];

let i = 0;
let ii: number;
while ((ii = lowerStr.indexOf(filterStr, i)) >= 0) {
// Push any text we missed (first bit/middle of text)
if (ii > i) {
// Push any text we aren't highlighting (middle of text match, or beginning of text)
result.push(<span key={i + "begin"}>{str.substring(i, ii)}</span>);
}

i = ii; // copy over ii only if we have a match (to preserve i for end-of-text matching)

// Highlight the word the user entered
const substr = str.substring(i, filterStr.length + i);
result.push(
<span className="mx_InviteDialog_tile--room_highlight" key={i + "bold"}>
{substr}
</span>,
);
i += substr.length;
}

// Push any text we missed (end of text)
if (i < str.length) {
result.push(<span key={i + "end"}>{str.substring(i)}</span>);
}

return result;
}

public render(): React.ReactNode {
let timestamp: JSX.Element | undefined;
if (this.props.lastActiveTs) {
const humanTs = humanizeTime(this.props.lastActiveTs);
timestamp = <span className="mx_InviteDialog_tile--room_time">{humanTs}</span>;
}

const avatarSize = "36px";
const avatarSize = "32px";
const avatar = (this.props.member as ThreepidMember).isEmail ? (
<EmailPillAvatarIcon width={avatarSize} height={avatarSize} />
) : (
Expand All @@ -241,40 +195,23 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
/>
);

let checkmark: JSX.Element | undefined;
if (this.props.isSelected) {
// To reduce flickering we put the 'selected' room tile above the real avatar
checkmark = <div className="mx_InviteDialog_tile--room_selected" />;
}

// To reduce flickering we put the checkmark on top of the actual avatar (prevents
// the browser from reloading the image source when the avatar remounts).
const stackedAvatar = (
<span className="mx_InviteDialog_tile_avatarStack">
{avatar}
{checkmark}
</span>
);

const userIdentifier = UserIdentifierCustomisations.getDisplayUserIdentifier(this.props.member.userId, {
withDisplayName: true,
});

const caption = (this.props.member as ThreepidMember).isEmail
? _t("invite|email_caption")
: this.highlightName(userIdentifier || this.props.member.userId);
: userIdentifier || this.props.member.userId;

return (
<AccessibleButton className="mx_InviteDialog_tile mx_InviteDialog_tile--room" onClick={this.onClick}>
{stackedAvatar}
<span className="mx_InviteDialog_tile_nameStack">
<div className="mx_InviteDialog_tile_nameStack_name">
{this.highlightName(this.props.member.name)}
</div>
<div className="mx_InviteDialog_tile_nameStack_userId">{caption}</div>
</span>
{timestamp}
</AccessibleButton>
<RichItem
avatar={avatar}
title={this.props.member.name}
description={caption}
timestamp={this.props.lastActiveTs}
onClick={this.onClick}
selected={this.props.isSelected}
/>
);
}
}
Expand Down Expand Up @@ -1048,8 +985,13 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
if (sourceMembers.length === 0 && !hasAdditionalMembers) {
return (
<div className="mx_InviteDialog_section">
<h3>{sectionName}</h3>
<p>{_t("common|no_results")}</p>
<RichList
title={sectionName}
titleAttributes={{ "role": "heading", "aria-level": 3 }}
isEmpty={true}
>
{_t("common|no_results")}
</RichList>
</div>
);
}
Expand Down Expand Up @@ -1084,14 +1026,15 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
lastActiveTs={lastActive(r)}
key={r.user.userId}
onToggle={this.toggleMember}
highlightWord={this.state.filterText}
isSelected={this.state.targets.some((t) => t.userId === r.userId)}
/>
));

return (
<div className="mx_InviteDialog_section">
<h3>{sectionName}</h3>
{tiles}
<RichList title={sectionName} titleAttributes={{ "role": "heading", "aria-level": 3 }}>
{tiles}
</RichList>
{showMore}
</div>
);
Expand Down
Loading
Loading