diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 89637224b2..c4fde34dab 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -88,7 +88,7 @@ "app-builder-lib": "26.12.1", "chokidar": "^5.0.0", "detect-libc": "^2.0.0", - "electron": "42.3.0", + "electron": "42.3.3", "electron-builder": "26.12.1", "electron-builder-squirrel-windows": "26.12.1", "electron-devtools-installer": "^4.0.0", diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index feb00601b0..51ecaeb628 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -14,8 +14,8 @@ WORKDIR /src # Install dependencies COPY --parents package.json pnpm-lock.yaml pnpm-workspace.yaml patches scripts **/package.json /src/ RUN corepack enable -RUN --mount=type=bind,source=.git,target=/src/.git /src/scripts/docker-link-repos.sh RUN pnpm install --frozen-lockfile +RUN --mount=type=bind,source=.git,target=/src/.git /src/scripts/docker-link-repos.sh # Build COPY --link --exclude=.git --exclude=apps/web/docker . /src diff --git a/apps/web/package.json b/apps/web/package.json index 593030139f..97562beab5 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -91,7 +91,7 @@ "opus-recorder": "^8.0.3", "pako": "^2.0.3", "png-chunks-extract": "^1.0.0", - "posthog-js": "1.376.6", + "posthog-js": "1.381.0", "qrcode": "1.5.4", "re-resizable": "6.11.2", "react": "catalog:", diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-custom-sections.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-custom-sections.spec.ts index b48345387f..29f95276fb 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-custom-sections.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-custom-sections.spec.ts @@ -371,5 +371,33 @@ test.describe("Room list custom sections", () => { // Room is back in the Chats section await assertRoomInSection(page, "Chats", "my room"); }); + + test("should remove a room from a custom section via the 'Remove from section' menu entry", async ({ + page, + app, + }) => { + await app.client.createRoom({ name: "my room" }); + await createCustomSection(page, "Work"); + + const roomList = getRoomList(page); + + // Move the room to the Work section + let roomItem = roomList.getByRole("row", { name: "Open room my room" }); + await roomItem.hover(); + await roomItem.getByRole("button", { name: "More Options" }).click(); + await page.getByRole("menuitem", { name: "Move to" }).hover(); + await page.getByRole("menuitem", { name: "Work" }).click(); + + await assertRoomInSection(page, "Work", "my room"); + + // Open the More Options menu and click "Remove from section" + roomItem = roomList.getByRole("row", { name: "Open room my room" }); + await roomItem.hover(); + await roomItem.getByRole("button", { name: "More Options" }).click(); + await page.getByRole("menuitem", { name: "Remove from section" }).click(); + + // Room is back in the Chats section + await assertRoomInSection(page, "Chats", "my room"); + }); }); }); diff --git a/apps/web/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png b/apps/web/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png index 4e4823da5b..7ce069ae94 100644 Binary files a/apps/web/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png and b/apps/web/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png differ diff --git a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-custom-sections.spec.ts/room-list-sections-chat-moved-toast-linux.png b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-custom-sections.spec.ts/room-list-sections-chat-moved-toast-linux.png index 52c7ce404a..ec388b8446 100644 Binary files a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-custom-sections.spec.ts/room-list-sections-chat-moved-toast-linux.png and b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-custom-sections.spec.ts/room-list-sections-chat-moved-toast-linux.png differ diff --git a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-collapsed-linux.png b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-collapsed-linux.png index 299579fc73..7709255251 100644 Binary files a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-collapsed-linux.png and b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-collapsed-linux.png differ diff --git a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-linux.png b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-linux.png index 626ef728ce..f9e558a6f6 100644 Binary files a/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-linux.png and b/apps/web/playwright/snapshots/left-panel/room-list-panel/room-list-sections.spec.ts/room-list-sections-linux.png differ diff --git a/apps/web/playwright/testcontainers/synapse.ts b/apps/web/playwright/testcontainers/synapse.ts index 39f8ef30bd..7b1db4b941 100644 --- a/apps/web/playwright/testcontainers/synapse.ts +++ b/apps/web/playwright/testcontainers/synapse.ts @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details. import { SynapseContainer as BaseSynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers/index.js"; const DOCKER_IMAGE = - "ghcr.io/element-hq/synapse:develop@sha256:3e079baccf55f491bd40c8b218789f0e8b31f466f6e23b14baab4a52ca845284"; + "ghcr.io/element-hq/synapse:develop@sha256:e5e02e25d3f3c38ae399acf74c359e971c2fd1381b88e0031a1faa9c785a0d91"; /** * SynapseContainer which freezes the docker digest to stabilise tests, diff --git a/apps/web/res/css/views/dialogs/_CreateSectionDialog.pcss b/apps/web/res/css/views/dialogs/_CreateSectionDialog.pcss index 7c941be39f..3198db4303 100644 --- a/apps/web/res/css/views/dialogs/_CreateSectionDialog.pcss +++ b/apps/web/res/css/views/dialogs/_CreateSectionDialog.pcss @@ -21,3 +21,7 @@ width: 100%; } } + +.mx_CreateSectionDialog_edition > .mx_Dialog_header { + margin-bottom: var(--cpd-space-6x); +} diff --git a/apps/web/res/css/views/dialogs/_DevtoolsDialog.pcss b/apps/web/res/css/views/dialogs/_DevtoolsDialog.pcss index f4c4dbcdcb..3ee2c9be53 100644 --- a/apps/web/res/css/views/dialogs/_DevtoolsDialog.pcss +++ b/apps/web/res/css/views/dialogs/_DevtoolsDialog.pcss @@ -35,6 +35,9 @@ Please see LICENSE files in the repository root for full details. .mx_DevTools_content { overflow-y: auto; + /* Give room for focus outlines */ + padding-inline-start: var(--cpd-space-0-5x); + padding-block-end: var(--cpd-space-0-5x); } .mx_DevTools_RoomStateExplorer_query { diff --git a/apps/web/src/components/structures/LoggedInView.tsx b/apps/web/src/components/structures/LoggedInView.tsx index 1a736ae696..24631ea617 100644 --- a/apps/web/src/components/structures/LoggedInView.tsx +++ b/apps/web/src/components/structures/LoggedInView.tsx @@ -202,8 +202,18 @@ class LoggedInView extends React.Component { OwnProfileStore.instance.on(UPDATE_EVENT, this.refreshBackgroundImage); this.refreshBackgroundImage(); + } - this.resizerViewModel = new ResizerViewModel(); + private getResizerViewModel(): ResizerViewModel { + if (!this.resizerViewModel) { + this.resizerViewModel = new ResizerViewModel(); + } + return this.resizerViewModel; + } + + private disposeResizerViewModel(): void { + this.resizerViewModel?.dispose(); + this.resizerViewModel = undefined; } /** @@ -739,6 +749,8 @@ class LoggedInView extends React.Component { break; default: { if (moduleRenderer) { + // Since the view will be removed, remove the vm as well + this.disposeResizerViewModel(); pageElement = moduleRenderer(); } else { console.warn(`Couldn't render page type "${this.props.page_type}"`); @@ -797,14 +809,15 @@ class LoggedInView extends React.Component { const roomView =
{pageElement}
; let content: React.ReactNode; - if (useNewRoomList && this.resizerViewModel && !moduleRenderer) { + const resizerViewModel = !moduleRenderer ? this.getResizerViewModel() : undefined; + if (useNewRoomList && resizerViewModel && !moduleRenderer) { // New room list owned by element-web: resizable layout with a draggable separator. // The SpacePanel lives inside GroupView (leftPanel omits it when the new room list is enabled). content = ( - + { > {leftPanel} - + {roomView} ); diff --git a/apps/web/src/components/views/dialogs/CreateSectionDialog.tsx b/apps/web/src/components/views/dialogs/CreateSectionDialog.tsx index d8aaed3326..717c80d015 100644 --- a/apps/web/src/components/views/dialogs/CreateSectionDialog.tsx +++ b/apps/web/src/components/views/dialogs/CreateSectionDialog.tsx @@ -8,6 +8,7 @@ import React, { useState, type JSX } from "react"; import { Flex } from "@element-hq/web-shared-components"; import { Form, Text } from "@vector-im/compound-web"; +import classNames from "classnames"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -37,15 +38,19 @@ export function CreateSectionDialog({ onFinished, sectionToEdit }: CreateSection return ( onFinished(false, value)} title={isEdition ? _t("create_section_dialog|title_edition") : _t("create_section_dialog|title")} hasCancel={true} > - - {_t("create_section_dialog|description")} - + {!isEdition && ( + + {_t("create_section_dialog|description")} + + )} { diff --git a/apps/web/src/i18n/strings/et.json b/apps/web/src/i18n/strings/et.json index b5f5996a43..01ebf58ae8 100644 --- a/apps/web/src/i18n/strings/et.json +++ b/apps/web/src/i18n/strings/et.json @@ -246,7 +246,9 @@ "check_code_heading": "Sisesta teises seadmes kuvatav number", "check_code_input_label": "2-kohaline kood", "check_code_mismatch": "Numbrid ei klapi", + "choose_desktop_computer": "Vali „%(desktopComputer)s“", "completing_setup": "Lõpetame uue seadme seadistamise", + "desktop_computer": "Lauaarvuti", "error_etag_missing": "Tekkis ootamatu viga. Selle põhjuseks võivad olla brauseri lisamoodul, proksiserveri seadistused või koduserveri vigased seadistused.", "error_expired": "Sisselogimine aegus. Palun proovi uuesti.", "error_expired_title": "Sisselogimine ei jõudnud õigeaegselt lõpule", @@ -267,15 +269,22 @@ "error_user_declined": "Sa keeldusid teises seadmes sisselogimispäringust.", "error_user_declined_title": "Sa keeldusid sisselogimast", "follow_remaining_instructions": "Teise seadme verifitseerimiseks järgi ülejäänud juhiseid", + "open_element_mobile_device": "Ava oma nutiseadmes %(brand)s", "open_element_other_device": "Ava %(brand)s oma teises seadmes", "point_the_camera": "Suuna kaamera siin näidatud QR-koodi peale", - "scan_code_instruction": "Skaneeri QR-koodi teise seadmega", + "ready_to_scan": "Skaneerimiseks valmis", + "scan_code_instruction": "Skaneeri seda QR-koodi", + "scan_code_instruction_reciprocate": "Skaneeri seda QR-koodi teise seadmega", "scan_qr_code": "Logi sisse QR-koodi alusel", - "security_code_prompt": "Kui seda küsitakse, sisesta teises seadmes allolev kood.", + "security_code_prompt": "Sinu teenusepakkuja võib sisselogimise verifitseerimiseks küsida seda koodi.", + "security_code_title": "Sinu verifitseerimiskood", "select_qr_code": "Val i „%(scanQRCode)s“", + "select_ready_to_scan": "Vali „%(readyToScan)s“ ja skaneeri siinnäidatud QR-koodi", + "start_over": "Alusta otsast peale", + "tap_avatar_link_new_device": "Klõpsa oma tunnuspilti ja vali „%(linkNewDevice)s“", "unsupported_explainer": "Sinu teenusepakkuja ei toeta võimalust logida sisse QR-koodi abil.", "unsupported_heading": "QR-koodi kasutamine pole toetatud", - "waiting_for_device": "Ootame, et teine seade logiks võrku" + "waiting_for_device": "Ootame sinu teise seadme järgi" }, "register_action": "Loo konto", "registration": { @@ -334,8 +343,10 @@ "sign_in_description": "Jätkamaks kasuta oma kontot.", "sign_in_instead": "Pigem logi sisse", "sign_in_instead_prompt": "Sul juba on kasutajakonto olemas? Siis logi siin sisse", + "sign_in_manually": "Logi sisse käsitsi", "sign_in_or_register": "Logi sisse või loo uus konto", "sign_in_or_register_description": "Jätkamaks kasuta oma kontot või loo uus konto.", + "sign_in_with_qr": "Logi sisse QR-koodi alusel", "sign_in_with_sso": "Logi sisse ühekordse sisselogimise abil", "signing_in": "Login sisse…", "soft_logout": { @@ -1517,6 +1528,7 @@ "bridge_state_manager": "Seda võrgusilda haldab .", "bridge_state_workspace": "Tööruum: ", "click_for_info": "Lisateabe jaoks klõpsi", + "config_only": "Saab sisselülitada ainult config.json failist.", "currently_experimental": "Parasjagu katsejärgus.", "custom_themes": "Kohandatud kujunduste lisamise võimalus", "dynamic_room_predecessors": "Jututoa dünaamilised eellased", @@ -1561,6 +1573,7 @@ "leave_beta_reload": "Beeta-funktsionaalsuste kasutamise lõpetamisel laadime uuesti rakenduse %(brand)s.", "location_share_live": "Asukoha jagamine reaalajas", "location_share_live_description": "Tegemist on ajutise ja esialgse lahendusega: asukohad on jututoa ajaloos näha.", + "login_with_qr": "Logi sisse QR-koodiga", "mjolnir": "Uued võimalused osalejate eiramiseks", "msc3531_hide_messages_pending_moderation": "Luba modereerimist ootavate sõnumite peitmist.", "new_room_list": "Võta kasutusele uus jututubade loend", diff --git a/apps/web/src/i18n/strings/fr.json b/apps/web/src/i18n/strings/fr.json index ed941d5c3e..e72c6ad4ff 100644 --- a/apps/web/src/i18n/strings/fr.json +++ b/apps/web/src/i18n/strings/fr.json @@ -270,11 +270,11 @@ "point_the_camera": "Scannez le QR code affiché ici", "scan_code_instruction": "Scannez le code QR", "scan_qr_code": "Se connecter avec un QR code", - "security_code_prompt": "Si vous y êtes invité, saisissez le code ci-dessous sur votre autre appareil.", + "security_code_prompt": "Votre fournisseur de compte peut vous demander le code suivant pour vérifier la connexion.", "select_qr_code": "Sélectionnez « %(scanQRCode)s »", "unsupported_explainer": "Votre fournisseur de compte ne prend pas en charge la connexion à un nouvel appareil à l’aide d’un code QR.", "unsupported_heading": "Le code QR n'est pas pris en charge", - "waiting_for_device": "En attente de connexion de l’appareil" + "waiting_for_device": "En attente de votre autre appareil" }, "register_action": "Créer un compte", "registration": { diff --git a/apps/web/src/i18n/strings/pl.json b/apps/web/src/i18n/strings/pl.json index c89bddd47c..c6c8622563 100644 --- a/apps/web/src/i18n/strings/pl.json +++ b/apps/web/src/i18n/strings/pl.json @@ -246,7 +246,9 @@ "check_code_heading": "Wprowadź numer wyświetlany na drugim urządzeniu", "check_code_input_label": "2-cyfrowy kod", "check_code_mismatch": "Liczby się nie zgadzają", + "choose_desktop_computer": "Wybierz \"%(desktopComputer)s\"", "completing_setup": "Kończenie konfiguracji nowego urządzenia", + "desktop_computer": "Komputer stacjonarny", "error_etag_missing": "Wystąpił nieoczekiwany błąd. Może to być spowodowane rozszerzeniem przeglądarki, serwerem proxy lub błędną konfiguracją serwera.", "error_expired": "Logowanie wygasło. Spróbuj ponownie.", "error_expired_title": "Logowanie nie zostało zakończone na czas", @@ -267,15 +269,22 @@ "error_user_declined": "Ty lub Twój dostawca konta odrzucił żądanie logowania.", "error_user_declined_title": "Logowanie odrzucone", "follow_remaining_instructions": "Postępuj zgodnie z pozostałymi instrukcjami, aby zweryfikować Twoje inne urządzenie", + "open_element_mobile_device": "Otwórz %(brand)s na swoim urządzeniu mobilnym", "open_element_other_device": "Otwórz %(brand)s na innym urządzeniu", "point_the_camera": "Skieruj kamerę na pokazany tutaj kod QR", - "scan_code_instruction": "Skanuj kod QR za pomocą innego urządzenia", + "ready_to_scan": "Gotowy do skanowania", + "scan_code_instruction": "Skanuj kod QR", + "scan_code_instruction_reciprocate": "Zeskanuj kod QR innym urządzeniem", "scan_qr_code": "Zaloguj się kodem QR", - "security_code_prompt": "Jeśli zostaniesz poproszony, wprowadź poniższy kod na drugim urządzeniu.", + "security_code_prompt": "Twój dostawca konta może poprosić o podany kod w celu weryfikacji logowania.", + "security_code_title": "Twój kod weryfikacyjny", "select_qr_code": "Wybierz '%(scanQRCode)s'", + "select_ready_to_scan": "Wybierz \"%(readyToScan)s\" i zeskanuj kod QR widoczny tutaj", + "start_over": "Zacznij od nowa", + "tap_avatar_link_new_device": "Kliknij swój awatar i wybierz \"%(linkNewDevice)s\"", "unsupported_explainer": "Twój dostawca konta nie obsługuje logowania nowego urządzenia za pomocą kodu QR.", "unsupported_heading": "Kod QR nie jest wspierany", - "waiting_for_device": "Oczekiwanie na logowanie urządzenia" + "waiting_for_device": "Oczekiwanie na drugie urządzenie" }, "register_action": "Utwórz konto", "registration": { @@ -334,8 +343,10 @@ "sign_in_description": "Użyj swojego konta, aby kontynuować.", "sign_in_instead": "Zamiast tego zaloguj się", "sign_in_instead_prompt": "Masz już konto? Zaloguj się tutaj ", + "sign_in_manually": "Zaloguj się ręcznie", "sign_in_or_register": "Zaloguj się lub utwórz konto", "sign_in_or_register_description": "Użyj konta lub utwórz nowe, aby kontynuować.", + "sign_in_with_qr": "Zaloguj się kodem QR", "sign_in_with_sso": "Zaloguj się za pomocą pojedynczego logowania", "signing_in": "Logowanie…", "soft_logout": { @@ -1528,6 +1539,7 @@ "bridge_state_manager": "Ten mostek jest zarządzany przez .", "bridge_state_workspace": "Obszar roboczy: ", "click_for_info": "Kliknij po więcej informacji", + "config_only": "Może zostać włączony tylko poprzez config.json.", "currently_experimental": "Aktualnie eksperymentalne.", "custom_themes": "Obsługa dodawania niestandardowych motywów", "dynamic_room_predecessors": "Dynamiczne poprzedniki pokoju", @@ -1572,6 +1584,7 @@ "leave_beta_reload": "Opuszczenie bety, wczyta ponownie %(brand)s.", "location_share_live": "Udostępnianie lokalizacji na żywo", "location_share_live_description": "Implementacja tymczasowa. Lokalizacje są zapisywane w historii pokoju.", + "login_with_qr": "Zaloguj się za pomocą kodu QR", "mjolnir": "Nowe sposoby na ignorowanie osób", "msc3531_hide_messages_pending_moderation": "Daj moderatorom ukrycie wiadomości które są sprawdzane.", "new_room_list": "Włącz nową listę pokojów", diff --git a/apps/web/src/settings/Settings.tsx b/apps/web/src/settings/Settings.tsx index a04da85104..8c47861bf8 100644 --- a/apps/web/src/settings/Settings.tsx +++ b/apps/web/src/settings/Settings.tsx @@ -1140,7 +1140,7 @@ export const SETTINGS: Settings = { "urlPreviewsEnabled": { // Enabled by default and client configurable as this setting only allows unencrypted // messages to be previewed. - supportedLevels: [SettingLevel.DEVICE, SettingLevel.ACCOUNT, SettingLevel.CONFIG], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.DEVICE, SettingLevel.ACCOUNT, SettingLevel.CONFIG], supportedLevelsAreOrdered: true, displayName: _td("settings|inline_url_previews_default"), default: true, diff --git a/apps/web/src/viewmodels/message-body/UrlPreviewGroupViewModel.ts b/apps/web/src/viewmodels/message-body/UrlPreviewGroupViewModel.ts index 025bc4e337..3ff1c40d3b 100644 --- a/apps/web/src/viewmodels/message-body/UrlPreviewGroupViewModel.ts +++ b/apps/web/src/viewmodels/message-body/UrlPreviewGroupViewModel.ts @@ -37,6 +37,8 @@ export const PREVIEW_WIDTH_PX = 478; export const PREVIEW_HEIGHT_PX = 200; export const MIN_PREVIEW_PX = 96; export const MIN_IMAGE_SIZE_BYTES = 8192; +// From https://github.com/matrix-org/matrix-spec-proposals/pull/4095 +export const BUNDLED_LINK_PREVIEWS = "com.beeper.linkpreviews"; export enum PreviewVisibility { /** @@ -387,6 +389,18 @@ export class UrlPreviewGroupViewModel * for the previously-calculated links. */ private async computeSnapshot(): Promise { + // This uses MSC4095. If the sender has sent us an empty URL previews bundle + // then they do not want to have URL previews be visible. + const bundledLinkPreviews = this.props.mxEvent.getContent()[BUNDLED_LINK_PREVIEWS]; + if (Array.isArray(bundledLinkPreviews) && bundledLinkPreviews.length === 0) { + return this.snapshot.merge({ + previews: [], + totalPreviewCount: 0, + previewsLimited: false, + overPreviewLimit: false, + }); + } // otherwise, we do not support bundled previews yet so will fallback to old behaviour. + const previews = this.visibility <= PreviewVisibility.UserHidden ? [] diff --git a/apps/web/src/viewmodels/room-list/RoomListItemViewModel.ts b/apps/web/src/viewmodels/room-list/RoomListItemViewModel.ts index 2f2f953ce6..b03b2e32ec 100644 --- a/apps/web/src/viewmodels/room-list/RoomListItemViewModel.ts +++ b/apps/web/src/viewmodels/room-list/RoomListItemViewModel.ts @@ -415,6 +415,14 @@ export class RoomListItemViewModel tagRoom(this.props.room, tag); }; + public onRemoveFromSection = (): void => { + const roomTags = this.props.room.tags; + const sectionTag = RoomListStoreV3.instance.orderedSectionTags.find((tag) => Boolean(roomTags[tag])); + if (sectionTag) { + tagRoom(this.props.room, sectionTag); + } + }; + private onOrderedCustomSectionsChange = (): void => { // Rebuild sections list to reflect new order const sections = RoomListItemViewModel.buildSections(this.props.room.tags); diff --git a/apps/web/test/viewmodels/message-body/UrlPreviewGroupViewModel-test.ts b/apps/web/test/viewmodels/message-body/UrlPreviewGroupViewModel-test.ts index 9541e999a8..d48c5711ff 100644 --- a/apps/web/test/viewmodels/message-body/UrlPreviewGroupViewModel-test.ts +++ b/apps/web/test/viewmodels/message-body/UrlPreviewGroupViewModel-test.ts @@ -9,7 +9,10 @@ import { expect } from "@jest/globals"; import type { MockedObject } from "jest-mock"; import type { MatrixClient, IPreviewUrlResponse } from "matrix-js-sdk/src/matrix"; -import { UrlPreviewGroupViewModel } from "../../../src/viewmodels/message-body/UrlPreviewGroupViewModel"; +import { + BUNDLED_LINK_PREVIEWS, + UrlPreviewGroupViewModel, +} from "../../../src/viewmodels/message-body/UrlPreviewGroupViewModel"; import type { UrlPreview } from "@element-hq/web-shared-components"; import { getMockClientWithEventEmitter, mkEvent } from "../../test-utils"; @@ -22,7 +25,9 @@ const BASIC_PREVIEW_OGDATA = { "og:site_name": "Example.org", }; -function getViewModel({ mediaVisible, visible } = { mediaVisible: true, visible: true }): { +function getViewModel( + { mediaVisible, visible, showPreview } = { mediaVisible: true, visible: true, showPreview: true }, +): { vm: UrlPreviewGroupViewModel; client: MockedObject; onImageClicked: jest.Mock; @@ -41,7 +46,9 @@ function getViewModel({ mediaVisible, visible } = { mediaVisible: true, visible: event: true, user: "@foo:bar", type: "m.room.message", - content: {}, + content: { + ...(showPreview ? undefined : { [BUNDLED_LINK_PREVIEWS]: [] }), + }, id: "$id", }), }); @@ -94,7 +101,7 @@ describe("UrlPreviewGroupViewModel", () => { ]); }); it("should hide preview when invisible", async () => { - const { vm, client } = getViewModel({ visible: false, mediaVisible: true }); + const { vm, client } = getViewModel({ visible: false, mediaVisible: true, showPreview: true }); const msg = document.createElement("div"); msg.innerHTML = 'Test'; await vm.updateEventElement(msg); @@ -152,7 +159,7 @@ describe("UrlPreviewGroupViewModel", () => { expect(vm.getSnapshot().previews[0].siteIcon).toBeTruthy(); }); it("should ignore media when mediaVisible is false", async () => { - const { vm, client } = getViewModel({ mediaVisible: false, visible: true }); + const { vm, client } = getViewModel({ mediaVisible: false, visible: true, showPreview: true }); client.getUrlPreview.mockResolvedValueOnce({ "og:title": "This is an example!", "og:type": "document", @@ -225,6 +232,21 @@ describe("UrlPreviewGroupViewModel", () => { await vm.onShowClick(); expect(vm.getSnapshot()).toMatchSnapshot(); }); + it("should hide a preview if the message requests it", async () => { + const { vm, client } = getViewModel({ showPreview: false, mediaVisible: true, visible: true }); + client.getUrlPreview.mockResolvedValueOnce(BASIC_PREVIEW_OGDATA); + const msg = document.createElement("div"); + msg.innerHTML = 'Test'; + await vm.updateEventElement(msg); + expect(vm.getSnapshot()).toMatchInlineSnapshot(` +{ + "overPreviewLimit": false, + "previews": [], + "previewsLimited": false, + "totalPreviewCount": 0, +} +`); + }); describe("calculates author", () => { it("should use the profile:username if provided", async () => { diff --git a/knip.ts b/knip.ts index 57d1e41294..88df16130a 100644 --- a/knip.ts +++ b/knip.ts @@ -55,7 +55,15 @@ export default { // Brought in via hak scripts "matrix-seshat", ], - ignoreBinaries: ["scripts/in-docker.sh"], + ignoreBinaries: [ + "scripts/in-docker.sh", + // Used to build seshat (optional) + "rustc", + // Used by the fetch-package script (optional) + "gpg", + // Used for the macOS universal builds + "lipo", + ], }, "modules/*": { entry: "src/index.ts{x,}", diff --git a/package.json b/package.json index 1b37c8f446..5ba5816887 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "cronstrue": "^3.0.0", "eslint-plugin-matrix-org": "^3.0.0", "husky": "^9.0.0", - "knip": "6.15.0", + "knip": "6.16.0", "lint-staged": "^17.0.0", "lodash": "^4.17.21", "mermaid": "^11.13.0", diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/chat-moved-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/chat-moved-auto.png index 0d4111e53b..937cecfb60 100644 Binary files a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/chat-moved-auto.png and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/chat-moved-auto.png differ diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/section-created-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/section-created-auto.png index 977772886a..b254ca100a 100644 Binary files a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/section-created-auto.png and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx/section-created-auto.png differ diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListView.stories.tsx/toast-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListView.stories.tsx/toast-auto.png index 722398dc96..b9401eaed2 100644 Binary files a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListView.stories.tsx/toast-auto.png and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListView/RoomListView.stories.tsx/toast-auto.png differ diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/VirtualizedRoomListView/RoomListItemDragOverlayView/RoomListItemDragOverlayView.stories.tsx/default-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/VirtualizedRoomListView/RoomListItemDragOverlayView/RoomListItemDragOverlayView.stories.tsx/default-auto.png index c65679e47f..2e5d6c7a1a 100644 Binary files a/packages/shared-components/__vis__/linux/__baselines__/room-list/VirtualizedRoomListView/RoomListItemDragOverlayView/RoomListItemDragOverlayView.stories.tsx/default-auto.png and b/packages/shared-components/__vis__/linux/__baselines__/room-list/VirtualizedRoomListView/RoomListItemDragOverlayView/RoomListItemDragOverlayView.stories.tsx/default-auto.png differ diff --git a/packages/shared-components/package.json b/packages/shared-components/package.json index 89430eeba6..87c5e1efbe 100644 --- a/packages/shared-components/package.json +++ b/packages/shared-components/package.json @@ -110,7 +110,7 @@ "@typescript-eslint/eslint-plugin": "^8.53.1", "@typescript-eslint/parser": "^8.53.1", "@vector-im/compound-web": "catalog:", - "@vitest/browser-playwright": "^4.0.17", + "@vitest/browser-playwright": "catalog:", "@vitest/coverage-v8": "catalog:", "eslint": "8", "eslint-config-google": "^0.14.0", diff --git a/packages/shared-components/src/i18n/strings/en_EN.json b/packages/shared-components/src/i18n/strings/en_EN.json index 823efba081..215fcb8013 100644 --- a/packages/shared-components/src/i18n/strings/en_EN.json +++ b/packages/shared-components/src/i18n/strings/en_EN.json @@ -150,7 +150,8 @@ "low_priority": "Low priority", "mark_read": "Mark as read", "mark_unread": "Mark as unread", - "move_to_section": "Move to" + "move_to_section": "Move to", + "remove_from_section": "Remove from section" }, "notification_options": "Notification options", "open_space_menu": "Open space menu", diff --git a/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx b/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx index c5c6530eee..f34e5b5a85 100644 --- a/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx +++ b/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.stories.tsx @@ -32,6 +32,12 @@ const meta = { ), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/qurBlLqjf3mRNpyZ1ffamm/ER-213---Sections?node-id=1233-22137&t=ftTEpAma7PgRaaqB-4", + }, + }, } satisfies Meta; export default meta; diff --git a/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.tsx b/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.tsx index e46b000fd4..1a2e4c194c 100644 --- a/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.tsx +++ b/packages/shared-components/src/room-list/RoomListView/RoomListToast/RoomListToast.tsx @@ -5,9 +5,8 @@ * Please see LICENSE files in the repository root for full details. */ -import React, { type ComponentType, type JSX, type MouseEventHandler } from "react"; +import React, { type JSX, type MouseEventHandler } from "react"; import { Toast } from "@vector-im/compound-web"; -import CheckIcon from "@vector-im/compound-design-tokens/assets/web/icons/check"; import styles from "./RoomListToast.module.css"; import { useI18n } from "../../../core/i18n/i18nContext"; @@ -32,19 +31,19 @@ interface RoomListToastProps { export function RoomListToast({ type, onClose }: Readonly): JSX.Element { const { translate: _t } = useI18n(); - let content: { text: string; icon: ComponentType> }; + let text: string; switch (type) { case "section_created": - content = { text: _t("room_list|section_created"), icon: CheckIcon }; + text = _t("room_list|section_created"); break; case "chat_moved": - content = { text: _t("room_list|chat_moved"), icon: CheckIcon }; + text = _t("room_list|chat_moved"); break; } return ( - - {content.text} + + {text} ); } diff --git a/packages/shared-components/src/room-list/RoomListView/RoomListToast/__snapshots__/RoomListToast.test.tsx.snap b/packages/shared-components/src/room-list/RoomListView/RoomListToast/__snapshots__/RoomListToast.test.tsx.snap index ee0c5946be..49e6f0e0d8 100644 --- a/packages/shared-components/src/room-list/RoomListView/RoomListToast/__snapshots__/RoomListToast.test.tsx.snap +++ b/packages/shared-components/src/room-list/RoomListView/RoomListToast/__snapshots__/RoomListToast.test.tsx.snap @@ -11,19 +11,6 @@ exports[` > renders ChatMoved story 1`] = `
- Chat moved