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

Implement new memberlist design with MVVM architecture #28874

Merged
merged 26 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
656d3e8
Add new e2e icon for the member tile
MidhunSureshR Jan 5, 2025
45c1bd1
Add new presence icon for member tile
MidhunSureshR Jan 5, 2025
7768795
Implement new member tile
MidhunSureshR Jan 5, 2025
4f50174
Implement memberlist view model
MidhunSureshR Jan 5, 2025
6eb51b3
Implement new memberlist header view
MidhunSureshR Jan 5, 2025
697d15a
Support the new memberlist in Diasambiguated profile
MidhunSureshR Jan 5, 2025
9eca64c
Implement new memberlist view
MidhunSureshR Jan 5, 2025
3561aec
Add and use a new overflow component
MidhunSureshR Jan 5, 2025
c27e2fb
Remove old code
MidhunSureshR Jan 5, 2025
cf0726d
Add/remove css files from _components.pcss
MidhunSureshR Jan 5, 2025
ceb8643
Increase minimum width as per design
MidhunSureshR Jan 5, 2025
e6e0360
Actually use the new memberlist view
MidhunSureshR Jan 5, 2025
41e20e5
Fix broken jest tests
MidhunSureshR Jan 5, 2025
a57d0b7
Add jest tests
MidhunSureshR Jan 5, 2025
2c4d3d5
Playwright: Make it possible to disable presence
MidhunSureshR Jan 5, 2025
0b28e20
Add playwright tests
MidhunSureshR Jan 5, 2025
ad96434
Fix lint error
MidhunSureshR Jan 5, 2025
ec78793
Undo translation changes that must be done via localazy
MidhunSureshR Jan 6, 2025
64ef538
Merge branch 'develop' into midhun/memberlist-redesign
MidhunSureshR Jan 6, 2025
9ac4da3
Update license header
MidhunSureshR Jan 6, 2025
0147e04
Use waitFor instead of setTimeout
MidhunSureshR Jan 6, 2025
80baac2
Remove comment
MidhunSureshR Jan 6, 2025
04413ed
Merge branch 'develop' into midhun/memberlist-redesign
MidhunSureshR Jan 8, 2025
9d35514
Switch over from template to container hs
MidhunSureshR Jan 8, 2025
37a6d09
Revert unintended change
MidhunSureshR Jan 8, 2025
2bf96cc
Move config to top level
MidhunSureshR Jan 8, 2025
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
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^8.0.0",
"@types/png-chunks-extract": "^1.0.2",
"@vector-im/compound-design-tokens": "^2.0.1",
"@vector-im/compound-design-tokens": "^2.1.0",
"@vector-im/compound-web": "^7.5.0",
"@vector-im/matrix-wysiwyg": "2.38.0",
"@zxcvbn-ts/core": "^3.0.4",
Expand Down Expand Up @@ -149,7 +149,9 @@
"temporal-polyfill": "^0.2.5",
"ua-parser-js": "^1.0.2",
"uuid": "^11.0.0",
"what-input": "^5.2.10"
"what-input": "^5.2.10",
"@types/react-virtualized": "^9.21.30",
"react-virtualized": "^9.22.5"
},
"devDependencies": {
"@action-validator/cli": "^0.6.0",
Expand Down
4 changes: 2 additions & 2 deletions playwright/e2e/crypto/dehydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const ROOM_NAME = "Test room";
const NAME = "Alice";

function getMemberTileByName(page: Page, name: string): Locator {
return page.locator(`.mx_EntityTile, [title="${name}"]`);
return page.locator(`.mx_MemberTileView, [title="${name}"]`);
}

test.describe("Dehydration", () => {
Expand Down Expand Up @@ -93,7 +93,7 @@ test.describe("Dehydration", () => {
await viewRoomSummaryByName(page, app, ROOM_NAME);

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

await getMemberTileByName(page, NAME).click();
await page.locator(".mx_UserInfo_devices .mx_UserInfo_expand").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 @@ -78,7 +78,7 @@ test.describe("Lazy Loading", () => {
}

function getMemberInMemberlist(page: Page, name: string): Locator {
return page.locator(".mx_MemberList .mx_EntityTile_name").filter({ hasText: name });
return page.locator(".mx_MemberListView .mx_MemberTileView_name").filter({ hasText: name });
}

async function checkMemberList(page: Page, charlies: Bot[]) {
Expand Down
43 changes: 43 additions & 0 deletions playwright/e2e/right-panel/memberlist.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2024 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { test, expect } from "../../element-web-test";
import { Bot } from "../../pages/bot";

const ROOM_NAME = "Test room";
const NAME = "Alice";

test.describe("Memberlist", () => {
test.use({
displayName: NAME,
startHomeserverOpts: "no-presence",
disablePresence: true,
});

test.beforeEach(async ({ app, user, page, homeserver }, testInfo) => {
testInfo.setTimeout(testInfo.timeout + 30_000);
const id = await app.client.createRoom({ name: ROOM_NAME });
const newBots: Bot[] = [];
const names = ["Bob", "Bob", "Susan"];
for (let i = 0; i < 3; i++) {
const displayName = names[i];
const autoAcceptInvites = displayName !== "Susan";
const bot = new Bot(page, homeserver, { displayName, startClient: true, autoAcceptInvites });
await bot.prepareClient();
await app.client.inviteUser(id, bot.credentials?.userId);
newBots.push(bot);
}
});

test("Renders correctly", { tag: "@screenshot" }, async ({ page, app }) => {
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(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png");

Check failure on line 41 in playwright/e2e/right-panel/memberlist.spec.ts

View workflow job for this annotation

GitHub Actions / Run Tests [Chrome] 4/6

[Chrome] › right-panel/memberlist.spec.ts:36:9 › Memberlist › Renders correctly @screenshot

1) [Chrome] › right-panel/memberlist.spec.ts:36:9 › Memberlist › Renders correctly @screenshot ─── Error: expect(locator).toHaveScreenshot(expected) 174 pixels (ratio 0.01 of all image pixels) are different. Expected: /home/runner/work/element-web/element-web/playwright/snapshots/right-panel/memberlist.spec.ts/with-four-members-linux.png Received: /home/runner/work/element-web/element-web/playwright/test-results/right-panel-memberlist-Memberlist-Renders-correctly-Chrome/with-four-members-actual.png Diff: /home/runner/work/element-web/element-web/playwright/test-results/right-panel-memberlist-Memberlist-Renders-correctly-Chrome/with-four-members-diff.png Call log: - expect.toHaveScreenshot(with-four-members.png) with timeout 5000ms - verifying given screenshot expectation - waiting for locator('.mx_MemberListView') - locator resolved to <div role="tabpanel" id="memberlist-panel" class="mx_BaseCard mx_MemberListView" aria-labelledby="memberlist-panel-tab">…</div> - taking element screenshot - disabled all CSS animations - waiting for fonts to load... - fonts loaded - attempting scroll into view action - waiting for element to be stable - 174 pixels (ratio 0.01 of all image pixels) are different. - waiting 100ms before taking screenshot - waiting for locator('.mx_MemberListView') - locator resolved to <div role="tabpanel" id="memberlist-panel" class="mx_BaseCard mx_MemberListView" aria-labelledby="memberlist-panel-tab">…</div> - taking element screenshot - disabled all CSS animations - waiting for fonts to load... - fonts loaded - attempting scroll into view action - waiting for element to be stable - captured a stable screenshot - 174 pixels (ratio 0.01 of all image pixels) are different. 39 | await expect(memberlist.locator(".mx_MemberTileView")).toHaveCount(4); 40 | await expect(memberlist.getByText("(Invited)")).toHaveCount(1); > 41 | await expect(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png"); | ^ 42 | }); 43 | }); 44 | at /home/runner/work/element-web/element-web/playwright/e2e/right-panel/memberlist.spec.ts:41:58
});
});
10 changes: 5 additions & 5 deletions playwright/e2e/right-panel/right-panel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const ROOM_ADDRESS_LONG =
"loremIpsumDolorSitAmetConsecteturAdipisicingElitSedDoEiusmodTemporIncididuntUtLaboreEtDoloreMagnaAliqua";

function getMemberTileByName(page: Page, name: string): Locator {
return page.locator(`.mx_EntityTile, [title="${name}"]`);
return page.locator(`.mx_MemberTileView, [title="${name}"]`);
}

test.describe("RightPanel", () => {
Expand Down Expand Up @@ -107,14 +107,14 @@ test.describe("RightPanel", () => {
await viewRoomSummaryByName(page, app, ROOM_NAME);

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

await getMemberTileByName(page, NAME).click();
await expect(page.locator(".mx_UserInfo")).toBeVisible();
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();

await page.getByTestId("base-card-back-button").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();
await expect(page.locator(".mx_MemberListView")).toBeVisible();

await page.getByLabel("Room info").nth(1).click();
await checkRoomSummaryCard(page, ROOM_NAME);
Expand All @@ -130,14 +130,14 @@ test.describe("RightPanel", () => {
.locator(".mx_RoomInfoLine_private")
.getByRole("button", { name: /\d member/ })
.click();
await expect(page.locator(".mx_MemberList")).toBeVisible();
await expect(page.locator(".mx_MemberListView")).toBeVisible();

await getMemberTileByName(page, NAME).click();
await expect(page.locator(".mx_UserInfo")).toBeVisible();
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();

await page.getByTestId("base-card-back-button").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();
await expect(page.locator(".mx_MemberListView")).toBeVisible();
});
});
});
9 changes: 8 additions & 1 deletion playwright/element-web-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export interface Fixtures {
bot: Bot;
labsFlags: string[];
webserver: Webserver;
disablePresence: boolean;
}

export const test = base.extend<Fixtures>({
Expand All @@ -133,8 +134,9 @@ export const test = base.extend<Fixtures>({
);
await use(context);
},
disablePresence: false,
config: CONFIG_JSON,
page: async ({ context, page, config, labsFlags }, use) => {
page: async ({ context, page, config, labsFlags, disablePresence, homeserver }, use) => {
await context.route(`http://localhost:8080/config.json*`, async (route) => {
const json = { ...CONFIG_JSON, ...config };
json["features"] = {
Expand All @@ -145,6 +147,11 @@ export const test = base.extend<Fixtures>({
return obj;
}, {}),
};
if (disablePresence) {
json["enable_presence_by_hs_url"] = {
[homeserver.config.baseUrl]: false,
};
}
await route.fulfill({ json });
});
await use(page);
Expand Down
12 changes: 12 additions & 0 deletions playwright/pages/ElementAppPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ export class ElementAppPage {
return this.page.locator(".mx_RightPanel");
}

/**
* Opens/closes the memberlist panel
* @returns locator to the memberlist panel
*/
public async toggleMemberlistPanel(): Promise<Locator> {
const locator = this.page.locator(".mx_FacePile");
await locator.click();
const memberlist = this.page.locator(".mx_MemberListView");
await memberlist.waitFor();
return memberlist;
}

/**
* Get a locator for the tooltip associated with an element
* @param e The element with the tooltip
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A synapse configured with presence disabled
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
server_name: "localhost"
pid_file: /data/homeserver.pid
public_baseurl: "{{PUBLIC_BASEURL}}"
listeners:
- port: 8008
tls: false
bind_addresses: ["::"]
type: http
x_forwarded: true

resources:
- names: [client]
compress: false

database:
name: "sqlite3"
args:
database: ":memory:"

log_config: "/data/log.config"

rc_messages_per_second: 10000
rc_message_burst_count: 10000
rc_registration:
per_second: 10000
burst_count: 10000
rc_joins:
local:
per_second: 9999
burst_count: 9999
remote:
per_second: 9999
burst_count: 9999
rc_joins_per_room:
per_second: 9999
burst_count: 9999
rc_3pid_validation:
per_second: 1000
burst_count: 1000

rc_invites:
per_room:
per_second: 1000
burst_count: 1000
per_user:
per_second: 1000
burst_count: 1000

rc_login:
address:
per_second: 10000
burst_count: 10000
account:
per_second: 10000
burst_count: 10000
failed_attempts:
per_second: 10000
burst_count: 10000

media_store_path: "/data/media_store"
uploads_path: "/data/uploads"
enable_registration: true
enable_registration_without_verification: true
disable_msisdn_registration: false
registration_shared_secret: "{{REGISTRATION_SECRET}}"
report_stats: false
macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
form_secret: "{{FORM_SECRET}}"
signing_key_path: "/data/localhost.signing.key"

trusted_key_servers:
- server_name: "matrix.org"
suppress_key_server_warning: true

ui_auth:
session_timeout: "300s"

oidc_providers:
- idp_id: test
idp_name: "OAuth test"
issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth"
authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html"
# the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container.
token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token"
userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo"
client_id: "synapse"
discover: false
scopes: ["profile"]
skip_verification: true
client_auth_method: none
user_mapping_provider:
config:
display_name_template: "{{ user.name }}"

# Inhibit background updates as this Synapse isn't long-lived
background_updates:
min_batch_size: 100000
sleep_duration_ms: 100000

experimental_features:
# Needed for e2e/crypto/crypto.spec.ts > Cryptography > decryption failure
# messages > non-joined historical messages.
# Can be removed after Synapse enables it by default
msc4115_membership_on_events: true

enable_authenticated_media: true

presence:
enabled: false
include_offline_users_on_sync: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Log configuration for Synapse.
#
# This is a YAML file containing a standard Python logging configuration
# dictionary. See [1] for details on the valid settings.
#
# Synapse also supports structured logging for machine readable logs which can
# be ingested by ELK stacks. See [2] for details.
#
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html

version: 1

formatters:
precise:
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'

handlers:
# A handler that writes logs to stderr. Unused by default, but can be used
# instead of "buffer" and "file" in the logger handlers.
console:
class: logging.StreamHandler
formatter: precise

loggers:
synapse.storage.SQL:
# beware: increasing this to DEBUG will make synapse log sensitive
# information such as access tokens.
level: DEBUG

twisted:
# We send the twisted logging directly to the file handler,
# to work around https://github.com/matrix-org/synapse/issues/3471
# when using "buffer" logger. Use "console" to log to stderr instead.
handlers: [console]
propagate: false

root:
level: DEBUG

# Write logs to the `buffer` handler, which will buffer them together in memory,
# then write them to a file.
#
# Replace "buffer" with "console" to log to stderr instead. (Note that you'll
# also need to update the configuration for the `twisted` logger above, in
# this case.)
#
handlers: [console]

disable_existing_loggers: false
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions res/css/_components.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,9 @@
@import "./views/rooms/_CallGuestLinkButton.pcss";
@import "./views/rooms/_DecryptionFailureBar.pcss";
@import "./views/rooms/_E2EIcon.pcss";
@import "./views/rooms/_E2EIconView.pcss";
@import "./views/rooms/_EditMessageComposer.pcss";
@import "./views/rooms/_EmojiButton.pcss";
@import "./views/rooms/_EntityTile.pcss";
@import "./views/rooms/_EventBubbleTile.pcss";
@import "./views/rooms/_EventPreview.pcss";
@import "./views/rooms/_EventTile.pcss";
Expand All @@ -290,13 +290,17 @@
@import "./views/rooms/_LinkPreviewGroup.pcss";
@import "./views/rooms/_LinkPreviewWidget.pcss";
@import "./views/rooms/_LiveContentSummary.pcss";
@import "./views/rooms/_MemberList.pcss";
@import "./views/rooms/_MemberListHeaderView.pcss";
@import "./views/rooms/_MemberListView.pcss";
@import "./views/rooms/_MemberTileView.pcss";
@import "./views/rooms/_MessageComposer.pcss";
@import "./views/rooms/_MessageComposerFormatBar.pcss";
@import "./views/rooms/_NewRoomIntro.pcss";
@import "./views/rooms/_NotificationBadge.pcss";
@import "./views/rooms/_OverflowTile.pcss";
@import "./views/rooms/_PinnedEventTile.pcss";
@import "./views/rooms/_PinnedMessageBanner.pcss";
@import "./views/rooms/_PresenceIconView.pcss";
@import "./views/rooms/_PresenceLabel.pcss";
@import "./views/rooms/_ReadReceiptGroup.pcss";
@import "./views/rooms/_ReplyPreview.pcss";
Expand Down
Loading
Loading