Skip to content

Commit

Permalink
Merge branch 'develop' into mention-text-and-pills-ux
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy authored Jan 22, 2025
2 parents 15aeec1 + ad01218 commit 6f95f12
Show file tree
Hide file tree
Showing 54 changed files with 1,318 additions and 1,121 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,4 @@ jobs:
projectName: ${{ env.SITE == 'staging.element.io' && 'element-web-staging' || 'element-web' }}
directory: _deploy
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
branch: main
2 changes: 1 addition & 1 deletion .github/workflows/dockerhub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- name: Build and push
id: build-and-push
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6
with:
context: .
push: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:

- name: Skip SonarCloud in merge queue
if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true'
uses: guibranco/github-status-action-v2@56cd38caf0615dd03f49d42ed301f1469911ac61
uses: guibranco/github-status-action-v2@ecd54a02cf761e85a8fb328fe937710fd4227cda
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: success
Expand Down
9 changes: 7 additions & 2 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
#### develop
The develop branch holds the very latest and greatest code we have to offer, as such it may be less stable. It corresponds to the develop.element.io CD platform.
The develop branch holds the very latest and greatest code we have to offer, as such it may be less stable.
It is auto-deployed on every commit to element-web or matrix-js-sdk to develop.element.io via GitHub Actions `build_develop.yml`.
#### staging
The staging branch corresponds to the very latest release regardless of whether it is an RC or not. Deployed to staging.element.io manually.
It is auto-deployed on every release of element-web to staging.element.io via GitHub Actions `deploy.yml`.
#### master
Expand Down Expand Up @@ -215,7 +217,7 @@ We ship Element Web to dockerhub, `*.element.io`, and packages.element.io.
We ship Element Desktop to packages.element.io.

- [ ] Check that element-web has shipped to dockerhub
- [ ] Deploy staging.element.io. [See docs.](https://handbook.element.io/books/element-web-team/page/deploying-appstagingelementio)
- [ ] Check that the staging [deployment](https://github.com/element-hq/element-web/actions/workflows/deploy.yml) has completed successfully
- [ ] Test staging.element.io

For final releases additionally do these steps:
Expand All @@ -225,6 +227,9 @@ For final releases additionally do these steps:
- [ ] Ensure Element Web package has shipped to packages.element.io
- [ ] Ensure Element Desktop packages have shipped to packages.element.io

If you need to roll back a deployment to staging.element.io,
you can run the `deploy.yml` automation choosing an older tag which you wish to deploy.

# Housekeeping

We have some manual housekeeping to do in order to prepare for the next release.
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"@types/react-dom": "18.3.5",
"oidc-client-ts": "3.1.0",
"jwt-decode": "4.0.0",
"caniuse-lite": "1.0.30001690",
"caniuse-lite": "1.0.30001692",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0",
"wrap-ansi": "npm:wrap-ansi@^7.0.0"
},
Expand Down Expand Up @@ -178,7 +178,7 @@
"@peculiar/webcrypto": "^1.4.3",
"@playwright/test": "^1.40.1",
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
"@sentry/webpack-plugin": "^2.7.1",
"@sentry/webpack-plugin": "^3.0.0",
"@stylistic/eslint-plugin": "^2.9.0",
"@svgr/webpack": "^8.0.0",
"@testcontainers/postgresql": "^10.16.0",
Expand Down Expand Up @@ -230,7 +230,7 @@
"dotenv": "^16.0.2",
"eslint": "8.57.1",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-deprecate": "0.8.5",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^28.0.0",
Expand Down Expand Up @@ -287,7 +287,7 @@
"terser-webpack-plugin": "^5.3.9",
"testcontainers": "^10.16.0",
"ts-node": "^10.9.1",
"typescript": "5.7.2",
"typescript": "5.7.3",
"util": "^0.12.5",
"web-streams-polyfill": "^4.0.0",
"webpack": "^5.89.0",
Expand Down
2 changes: 1 addition & 1 deletion playwright/e2e/right-panel/memberlist.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ test.describe("Memberlist", () => {
await app.viewRoomByName(ROOM_NAME);
const memberlist = await app.toggleMemberlistPanel();
await expect(memberlist.locator(".mx_MemberTileView")).toHaveCount(4);
await expect(memberlist.getByText("(Invited)")).toHaveCount(1);
await expect(memberlist.getByText("Invited")).toHaveCount(1);
await expect(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png");
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion playwright/testcontainers/synapse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { HomeserverContainer, StartedHomeserverContainer } from "./HomeserverCon
import { StartedMatrixAuthenticationServiceContainer } from "./mas.ts";
import { Api, ClientServerApi, Verb } from "../plugins/utils/api.ts";

const TAG = "develop@sha256:5d62b61c4373eaca25df6c6bb99fc1be92f8f40b8abebd8897bf5b2af9eb137a";
const TAG = "develop@sha256:3594fba0d21ad44f407225baed4be0542da8abcb6e1a7e2e16d3be35c278a7cb";

const DEFAULT_CONFIG = {
server_name: "localhost",
Expand Down
1 change: 1 addition & 0 deletions res/css/_components.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@
@import "./views/rooms/_EventTile.pcss";
@import "./views/rooms/_HistoryTile.pcss";
@import "./views/rooms/_IRCLayout.pcss";
@import "./views/rooms/_InvitedIconView.pcss";
@import "./views/rooms/_JumpToBottomButton.pcss";
@import "./views/rooms/_LinkPreviewGroup.pcss";
@import "./views/rooms/_LinkPreviewWidget.pcss";
Expand Down
2 changes: 2 additions & 0 deletions res/css/views/messages/_DisambiguatedProfile.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Please see LICENSE files in the repository root for full details.
.mx_DisambiguatedProfile_mxid {
margin-inline-start: 0;
font: var(--cpd-font-body-sm-regular);
text-overflow: ellipsis;
overflow: hidden;
}

span:not(.mx_DisambiguatedProfile_mxid) {
Expand Down
10 changes: 10 additions & 0 deletions res/css/views/rooms/_InvitedIconView.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

.mx_InvitedIconView {
color: var(--cpd-color-icon-tertiary);
}
6 changes: 6 additions & 0 deletions res/css/views/rooms/_MemberListView.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ Please see LICENSE files in the repository root for full details.
.mx_MemberListView_container {
height: 100%;
}

.mx_MemberListView_separator {
margin: 0;
border: none;
border-top: 2px solid var(--cpd-color-bg-subtle-primary);
}
}
18 changes: 3 additions & 15 deletions res/css/views/rooms/_MemberTileView.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,16 @@ Please see LICENSE files in the repository root for full details.
min-width: 0;
}

.mx_MemberTileView_user_label {
.mx_MemberTileView_userLabel {
font: var(--cpd-font-body-sm-regular);
font-size: 13px;
color: var(--cpd-color-text-secondary);
margin-left: var(--cpd-space-4x);
}

.mx_MemberTileView_avatar {
position: relative;
height: 32px;
width: 32px;
}

.mx_E2EIconView {
display: flex;
justify-content: center;
align-items: center;
}

.mx_E2EIconView_warning {
color: var(--cpd-color-icon-critical-primary);
}

.mx_E2EIconView_verified {
color: var(--cpd-color-icon-success-primary);
}
}
43 changes: 32 additions & 11 deletions src/components/viewmodels/memberlist/MemberListViewModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,12 @@ export function sdkRoomMemberToRoomMember(member: SdkRoomMember): Member {
};
}

export const SEPARATOR = "SEPARATOR";
export type MemberWithSeparator = Member | typeof SEPARATOR;

export interface MemberListViewState {
members: Member[];
members: MemberWithSeparator[];
memberCount: number;
search: (searchQuery: string) => void;
isPresenceEnabled: boolean;
shouldShowInvite: boolean;
Expand All @@ -118,10 +122,16 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {
}

const sdkContext = useContext(SDKContext);
const [memberMap, setMemberMap] = useState<Map<string, Member>>(new Map());
const [memberMap, setMemberMap] = useState<Map<string, MemberWithSeparator>>(new Map());
const [isLoading, setIsLoading] = useState<boolean>(true);
// This is the last known total number of members in this room.
const [totalMemberCount, setTotalMemberCount] = useState(0);
/**
* This is the current number of members in the list.
* This number will be less than the total number of members
* in the room when the search functionality is used.
*/
const [memberCount, setMemberCount] = useState(0);

const loadMembers = useMemo(
() =>
Expand All @@ -131,24 +141,34 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {
roomId,
searchQuery,
);
const newMemberMap = new Map<string, Member>();
// First add the invited room members
const threePidInvited = getPending3PidInvites(room, searchQuery);

const newMemberMap = new Map<string, MemberWithSeparator>();

// First add the joined room members
for (const member of joinedSdk) {
const roomMember = sdkRoomMemberToRoomMember(member);
newMemberMap.set(member.userId, roomMember);
}

// Then a separator if needed
if (joinedSdk.length > 0 && (invitedSdk.length > 0 || threePidInvited.length > 0))
newMemberMap.set(SEPARATOR, SEPARATOR);

// Then add the invited room members
for (const member of invitedSdk) {
const roomMember = sdkRoomMemberToRoomMember(member);
newMemberMap.set(member.userId, roomMember);
}
// Then add the third party invites
const threePidInvited = getPending3PidInvites(room, searchQuery);

// Finally add the third party invites
for (const invited of threePidInvited) {
const key = invited.threePidInvite!.event.getContent().display_name;
newMemberMap.set(key, invited);
}
// Finally add the joined room members
for (const member of joinedSdk) {
const roomMember = sdkRoomMemberToRoomMember(member);
newMemberMap.set(member.userId, roomMember);
}

setMemberMap(newMemberMap);
setMemberCount(joinedSdk.length + invitedSdk.length + threePidInvited.length);
if (!searchQuery) {
/**
* Since searching for members only gives you the relevant
Expand Down Expand Up @@ -241,6 +261,7 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {

return {
members: Array.from(memberMap.values()),
memberCount,
search: loadMembers,
shouldShowInvite,
isPresenceEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export function useMemberTileViewModel(props: MemberTileViewModelProps): MemberT
userLabel = _t(PowerLabel[powerStatus]);
}
if (props.member.isInvite) {
userLabel = `(${_t("member_list|invited_label")})`;
userLabel = _t("member_list|invited_label");
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
import dis from "../../../../dispatcher/dispatcher";
import { Action } from "../../../../dispatcher/actions";
import { ThreePIDInvite } from "../../../../models/rooms/ThreePIDInvite";
import { _t } from "../../../../languageHandler";

interface ThreePidTileViewModelProps {
threePidInvite: ThreePIDInvite;
Expand All @@ -16,6 +17,7 @@ interface ThreePidTileViewModelProps {
export interface ThreePidTileViewState {
name: string;
onClick: () => void;
userLabel?: string;
}

export function useThreePidTileViewModel(props: ThreePidTileViewModelProps): ThreePidTileViewState {
Expand All @@ -28,8 +30,11 @@ export function useThreePidTileViewModel(props: ThreePidTileViewModelProps): Thr
});
};

const userLabel = _t("member_list|invited_label");

return {
name,
onClick,
userLabel,
};
}
4 changes: 2 additions & 2 deletions src/components/views/elements/LabelledToggleSwitch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.

import React from "react";
import classNames from "classnames";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";

import ToggleSwitch from "./ToggleSwitch";
import { Caption } from "../typography/Caption";
Expand Down Expand Up @@ -36,7 +36,7 @@ interface IProps {
}

export default class LabelledToggleSwitch extends React.PureComponent<IProps> {
private readonly id = `mx_LabelledToggleSwitch_${randomString(12)}`;
private readonly id = `mx_LabelledToggleSwitch_${secureRandomString(12)}`;

public render(): React.ReactNode {
// This is a minimal version of a SettingsFlag
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/elements/SettingsFlag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
*/

import React from "react";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";

import SettingsStore from "../../../settings/SettingsStore";
import { _t } from "../../../languageHandler";
Expand All @@ -35,7 +35,7 @@ interface IState {
}

export default class SettingsFlag extends React.Component<IProps, IState> {
private readonly id = `mx_SettingsFlag_${randomString(12)}`;
private readonly id = `mx_SettingsFlag_${secureRandomString(12)}`;

public constructor(props: IProps) {
super(props);
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/elements/StyledCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/

import React, { Ref } from "react";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import classnames from "classnames";

export enum CheckboxStyle {
Expand All @@ -33,7 +33,7 @@ export default class StyledCheckbox extends React.PureComponent<IProps, IState>
public constructor(props: IProps) {
super(props);
// 56^10 so unlikely chance of collision.
this.id = this.props.id || "checkbox_" + randomString(10);
this.id = this.props.id || "checkbox_" + secureRandomString(10);
}

public render(): React.ReactNode {
Expand Down
6 changes: 3 additions & 3 deletions src/components/views/messages/MBeaconBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
ContentHelpers,
M_BEACON,
} from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import classNames from "classnames";

import MatrixClientContext from "../../../contexts/MatrixClientContext";
Expand Down Expand Up @@ -81,10 +81,10 @@ const useBeaconState = (
// eg thread and main timeline, reply
// maplibregl needs a unique id to attach the map instance to
const useUniqueId = (eventId: string): string => {
const [id, setId] = useState(`${eventId}_${randomString(8)}`);
const [id, setId] = useState(`${eventId}_${secureRandomString(8)}`);

useEffect(() => {
setId(`${eventId}_${randomString(8)}`);
setId(`${eventId}_${secureRandomString(8)}`);
}, [eventId]);

return id;
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/messages/MLocationBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.

import React from "react";
import { MatrixEvent, ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { Tooltip } from "@vector-im/compound-web";

import { _t } from "../../../languageHandler";
Expand Down Expand Up @@ -41,7 +41,7 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {

// multiple instances of same map might be in document
// eg thread and main timeline, reply
const idSuffix = `${props.mxEvent.getId()}_${randomString(8)}`;
const idSuffix = `${props.mxEvent.getId()}_${secureRandomString(8)}`;
this.mapId = `mx_MLocationBody_${idSuffix}`;

this.reconnectedListener = createReconnectedListener(this.clearError);
Expand Down
Loading

0 comments on commit 6f95f12

Please sign in to comment.