Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/dedup-icons

This commit is contained in:
Michael Telatynski
2024-07-22 13:52:26 +01:00
47 changed files with 267 additions and 398 deletions
@@ -50,7 +50,7 @@ test.describe("FilePanel", () => {
test.describe("render", () => { test.describe("render", () => {
test("should render empty state", async ({ page }) => { test("should render empty state", async ({ page }) => {
// Wait until the information about the empty state is rendered // Wait until the information about the empty state is rendered
await expect(page.locator(".mx_FilePanel_empty")).toBeVisible(); await expect(page.locator(".mx_EmptyState")).toBeVisible();
// Take a snapshot of RightPanel - fix https://github.com/vector-im/element-web/issues/25332 // Take a snapshot of RightPanel - fix https://github.com/vector-im/element-web/issues/25332
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png"); await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png");
@@ -35,7 +35,7 @@ test.describe("NotificationPanel", () => {
await page.getByRole("button", { name: "Notifications" }).click(); await page.getByRole("button", { name: "Notifications" }).click();
// Wait until the information about the empty state is rendered // Wait until the information about the empty state is rendered
await expect(page.locator(".mx_NotificationPanel_empty")).toBeVisible(); await expect(page.locator(".mx_EmptyState")).toBeVisible();
// Take a snapshot of RightPanel // Take a snapshot of RightPanel
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png"); await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png");
@@ -104,7 +104,7 @@ test.describe("RightPanel", () => {
await page.getByRole("menuitem", { name: "Files" }).click(); await page.getByRole("menuitem", { name: "Files" }).click();
await expect(page.locator(".mx_FilePanel")).toBeVisible(); await expect(page.locator(".mx_FilePanel")).toBeVisible();
await expect(page.locator(".mx_FilePanel_empty")).toBeVisible(); await expect(page.locator(".mx_EmptyState")).toBeVisible();
await page.getByTestId("base-card-back-button").click(); await page.getByTestId("base-card-back-button").click();
await checkRoomSummaryCard(page, ROOM_NAME); await checkRoomSummaryCard(page, ROOM_NAME);
@@ -28,7 +28,7 @@ import { randB64Bytes } from "../../utils/rand";
// Docker tag to use for `matrixdotorg/synapse` image. // Docker tag to use for `matrixdotorg/synapse` image.
// We target a specific digest as every now and then a Synapse update will break our CI. // We target a specific digest as every now and then a Synapse update will break our CI.
// This digest is updated by the playwright-image-updates.yaml workflow periodically. // This digest is updated by the playwright-image-updates.yaml workflow periodically.
const DOCKER_TAG = "develop@sha256:ee66fc1ebbf15f9dde375cdb2afd544491b88b81ac3c82e6c4282bc3b7f332bc"; const DOCKER_TAG = "develop@sha256:14ca769c834220a478a1e97df041361c6fb0a541ccb2f0666d3ce911224f5f7e";
async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise<Omit<HomeserverConfig, "dockerUrl">> { async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise<Omit<HomeserverConfig, "dockerUrl">> {
const templateDir = path.join(__dirname, "templates", opts.template); const templateDir = path.join(__dirname, "templates", opts.template);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 70 KiB

+1 -1
View File
@@ -73,7 +73,6 @@
@import "./structures/_MatrixChat.pcss"; @import "./structures/_MatrixChat.pcss";
@import "./structures/_MessagePanel.pcss"; @import "./structures/_MessagePanel.pcss";
@import "./structures/_NonUrgentToastContainer.pcss"; @import "./structures/_NonUrgentToastContainer.pcss";
@import "./structures/_NotificationPanel.pcss";
@import "./structures/_QuickSettingsButton.pcss"; @import "./structures/_QuickSettingsButton.pcss";
@import "./structures/_RightPanel.pcss"; @import "./structures/_RightPanel.pcss";
@import "./structures/_RoomSearch.pcss"; @import "./structures/_RoomSearch.pcss";
@@ -259,6 +258,7 @@
@import "./views/polls/pollHistory/_PollHistory.pcss"; @import "./views/polls/pollHistory/_PollHistory.pcss";
@import "./views/polls/pollHistory/_PollHistoryList.pcss"; @import "./views/polls/pollHistory/_PollHistoryList.pcss";
@import "./views/right_panel/_BaseCard.pcss"; @import "./views/right_panel/_BaseCard.pcss";
@import "./views/right_panel/_EmptyState.pcss";
@import "./views/right_panel/_EncryptionInfo.pcss"; @import "./views/right_panel/_EncryptionInfo.pcss";
@import "./views/right_panel/_PinnedMessagesCard.pcss"; @import "./views/right_panel/_PinnedMessagesCard.pcss";
@import "./views/right_panel/_RightPanelTabs.pcss"; @import "./views/right_panel/_RightPanelTabs.pcss";
-4
View File
@@ -102,7 +102,3 @@ limitations under the License.
padding-inline-start: 0; padding-inline-start: 0;
} }
} }
.mx_FilePanel_empty::before {
--maskImage: url("$(res)/img/element-icons/room/files.svg"); /* See: _RightPanel.pcss */
}
@@ -1,19 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_NotificationPanel_empty::before {
--maskImage: url("$(res)/img/element-icons/notifications.svg"); /* See: _RightPanel.pcss */
}
-27
View File
@@ -72,30 +72,3 @@ limitations under the License.
order: 2; order: 2;
margin: auto; margin: auto;
} }
.mx_RightPanel_empty {
margin-right: -28px;
h2 {
font-weight: 700;
margin: 16px 0;
}
h2,
p {
font: var(--cpd-font-body-md-regular);
}
&::before {
content: "";
display: block;
margin: 11px auto 29px auto;
height: 42px;
width: 42px;
background-color: $header-panel-text-primary-color;
mask-image: var(--maskImage);
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
}
}
@@ -0,0 +1,45 @@
/*
Copyright 2024 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_EmptyState {
height: 100%;
box-sizing: border-box;
padding: var(--cpd-space-4x);
text-align: center;
svg {
width: 56px;
height: 56px;
box-sizing: border-box;
border-radius: 8px;
padding: var(--cpd-space-3x);
background-color: $panel-actions;
}
&::before {
/* Bloom using magic numbers directly out of Figma */
content: "";
position: absolute;
z-index: -1;
width: 642px;
height: 775px;
right: -253.77px;
top: 0;
background: radial-gradient(49.95% 49.95% at 50% 50%, rgba(13, 189, 139, 0.12) 0%, rgba(18, 115, 235, 0) 100%);
transform: rotate(-89.69deg);
overflow: hidden;
}
}
+8 -67
View File
@@ -106,10 +106,17 @@ limitations under the License.
} }
.mx_RoomView_messagePanel { .mx_RoomView_messagePanel {
/* To avoid the rule from being applied to .mx_ThreadPanel_empty */ &.mx_RoomView_messageListWrapper {
position: initial;
}
.mx_RoomView_messageListWrapper { .mx_RoomView_messageListWrapper {
width: calc(100% + 6px); /* 8px - 2px */ width: calc(100% + 6px); /* 8px - 2px */
} }
.mx_RoomView_empty {
display: contents;
}
} }
.mx_RoomView_MessageList { .mx_RoomView_MessageList {
@@ -168,72 +175,6 @@ limitations under the License.
mask-image: url("@vector-im/compound-design-tokens/icons/link.svg"); mask-image: url("@vector-im/compound-design-tokens/icons/link.svg");
} }
.mx_ThreadPanel_empty {
border-radius: 8px;
background: $background;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
padding: 20px;
box-sizing: border-box; /* Include padding and border */
width: 100%;
h2 {
color: $primary-content;
font-weight: var(--cpd-font-weight-semibold);
font-size: $font-18px;
margin-top: 24px;
margin-bottom: 10px;
}
p {
font-size: $font-15px;
color: $secondary-content;
margin: 10px 0;
}
button {
border: none;
background: none;
color: $accent;
font-size: $font-15px;
&:hover,
&:active {
text-decoration: underline;
cursor: pointer;
}
}
.mx_ThreadPanel_empty_tip {
font-size: $font-12px;
line-height: $font-15px;
> b {
font-weight: var(--cpd-font-weight-semibold);
}
}
}
.mx_ThreadPanel_largeIcon {
width: 28px;
height: 28px;
padding: 18px;
background: $system;
border-radius: 50%;
&::after {
@mixin ThreadSummaryIcon;
width: inherit;
height: inherit;
}
}
.mx_ContextualMenu_wrapper { .mx_ContextualMenu_wrapper {
.mx_ThreadPanel_Header_FilterOptionItem { .mx_ThreadPanel_Header_FilterOptionItem {
display: flex; display: flex;
+7 -4
View File
@@ -28,6 +28,7 @@ import {
TimelineWindow, TimelineWindow,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Icon as FilesIcon } from "@vector-im/compound-design-tokens/icons/files.svg";
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { MatrixClientPeg } from "../../MatrixClientPeg";
import EventIndexPeg from "../../indexing/EventIndexPeg"; import EventIndexPeg from "../../indexing/EventIndexPeg";
@@ -40,6 +41,7 @@ import Spinner from "../views/elements/Spinner";
import { Layout } from "../../settings/enums/Layout"; import { Layout } from "../../settings/enums/Layout";
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
import Measured from "../views/elements/Measured"; import Measured from "../views/elements/Measured";
import EmptyState from "../views/right_panel/EmptyState";
interface IProps { interface IProps {
roomId: string; roomId: string;
@@ -255,10 +257,11 @@ class FilePanel extends React.Component<IProps, IState> {
// wrap a TimelinePanel with the jump-to-event bits turned off. // wrap a TimelinePanel with the jump-to-event bits turned off.
const emptyState = ( const emptyState = (
<div className="mx_RightPanel_empty mx_FilePanel_empty"> <EmptyState
<h2>{_t("file_panel|empty_heading")}</h2> Icon={FilesIcon}
<p>{_t("file_panel|empty_description")}</p> title={_t("file_panel|empty_heading")}
</div> description={_t("file_panel|empty_description")}
/>
); );
const isRoomEncrypted = this.noRoom ? false : MatrixClientPeg.safeGet().isRoomEncrypted(this.props.roomId); const isRoomEncrypted = this.noRoom ? false : MatrixClientPeg.safeGet().isRoomEncrypted(this.props.roomId);
@@ -16,6 +16,7 @@ limitations under the License.
import React from "react"; import React from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Icon as NotificationsIcon } from "@vector-im/compound-design-tokens/icons/notifications.svg";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { MatrixClientPeg } from "../../MatrixClientPeg";
@@ -26,6 +27,7 @@ import { Layout } from "../../settings/enums/Layout";
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
import Measured from "../views/elements/Measured"; import Measured from "../views/elements/Measured";
import Heading from "../views/typography/Heading"; import Heading from "../views/typography/Heading";
import EmptyState from "../views/right_panel/EmptyState";
interface IProps { interface IProps {
onClose(): void; onClose(): void;
@@ -57,10 +59,11 @@ export default class NotificationPanel extends React.PureComponent<IProps, IStat
public render(): React.ReactNode { public render(): React.ReactNode {
const emptyState = ( const emptyState = (
<div className="mx_RightPanel_empty mx_NotificationPanel_empty"> <EmptyState
<h2>{_t("notif_panel|empty_heading")}</h2> Icon={NotificationsIcon}
<p>{_t("notif_panel|empty_description")}</p> title={_t("notif_panel|empty_heading")}
</div> description={_t("notif_panel|empty_description")}
/>
); );
let content: JSX.Element; let content: JSX.Element;
+28 -91
View File
@@ -19,6 +19,7 @@ import React, { useContext, useEffect, useRef, useState } from "react";
import { EventTimelineSet, Room, Thread } from "matrix-js-sdk/src/matrix"; import { EventTimelineSet, Room, Thread } from "matrix-js-sdk/src/matrix";
import { IconButton, Tooltip } from "@vector-im/compound-web"; import { IconButton, Tooltip } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Icon as ThreadsIcon } from "@vector-im/compound-design-tokens/icons/threads.svg";
import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg"; import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg";
import BaseCard from "../views/right_panel/BaseCard"; import BaseCard from "../views/right_panel/BaseCard";
@@ -37,6 +38,7 @@ import { ButtonEvent } from "../views/elements/AccessibleButton";
import Spinner from "../views/elements/Spinner"; import Spinner from "../views/elements/Spinner";
import Heading from "../views/typography/Heading"; import Heading from "../views/typography/Heading";
import { clearRoomNotification } from "../../utils/notifications"; import { clearRoomNotification } from "../../utils/notifications";
import EmptyState from "../views/right_panel/EmptyState";
interface IProps { interface IProps {
roomId: string; roomId: string;
@@ -73,8 +75,7 @@ export const ThreadPanelHeaderFilterOptionItem: React.FC<
export const ThreadPanelHeader: React.FC<{ export const ThreadPanelHeader: React.FC<{
filterOption: ThreadFilterType; filterOption: ThreadFilterType;
setFilterOption: (filterOption: ThreadFilterType) => void; setFilterOption: (filterOption: ThreadFilterType) => void;
empty: boolean; }> = ({ filterOption, setFilterOption }) => {
}> = ({ filterOption, setFilterOption, empty }) => {
const mxClient = useMatrixClientContext(); const mxClient = useMatrixClientContext();
const roomContext = useRoomContext(); const roomContext = useRoomContext();
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>(); const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>();
@@ -140,86 +141,24 @@ export const ThreadPanelHeader: React.FC<{
<Heading size="4" className="mx_BaseCard_header_title_heading"> <Heading size="4" className="mx_BaseCard_header_title_heading">
{_t("common|threads")} {_t("common|threads")}
</Heading> </Heading>
{!empty && ( <Tooltip label={_t("threads|mark_all_read")}>
<> <IconButton onClick={onMarkAllThreadsReadClick} aria-label={_t("threads|mark_all_read")} size="24px">
<Tooltip label={_t("threads|mark_all_read")}> <MarkAllThreadsReadIcon />
<IconButton </IconButton>
onClick={onMarkAllThreadsReadClick} </Tooltip>
aria-label={_t("threads|mark_all_read")} <div className="mx_ThreadPanel_vertical_separator" />
size="24px" <ContextMenuButton
> className="mx_ThreadPanel_dropdown"
<MarkAllThreadsReadIcon /> ref={button}
</IconButton> isExpanded={menuDisplayed}
</Tooltip> onClick={(ev: ButtonEvent) => {
<div className="mx_ThreadPanel_vertical_separator" /> openMenu();
<ContextMenuButton PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev);
className="mx_ThreadPanel_dropdown" }}
ref={button} >
isExpanded={menuDisplayed} {`${_t("threads|show_thread_filter")} ${value?.label}`}
onClick={(ev: ButtonEvent) => { </ContextMenuButton>
openMenu(); {contextMenu}
PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev);
}}
>
{`${_t("threads|show_thread_filter")} ${value?.label}`}
</ContextMenuButton>
{contextMenu}
</>
)}
</div>
);
};
interface EmptyThreadIProps {
hasThreads: boolean;
filterOption: ThreadFilterType;
showAllThreadsCallback: () => void;
}
const EmptyThread: React.FC<EmptyThreadIProps> = ({ hasThreads, filterOption, showAllThreadsCallback }) => {
let body: JSX.Element;
if (hasThreads) {
body = (
<>
<p>
{_t("threads|empty_has_threads_tip", {
replyInThread: _t("action|reply_in_thread"),
})}
</p>
<p>
{/* Always display that paragraph to prevent layout shift when hiding the button */}
{filterOption === ThreadFilterType.My ? (
<button onClick={showAllThreadsCallback}>{_t("threads|show_all_threads")}</button>
) : (
<>&nbsp;</>
)}
</p>
</>
);
} else {
body = (
<>
<p>{_t("threads|empty_explainer")}</p>
<p className="mx_ThreadPanel_empty_tip">
{_t(
"threads|empty_tip",
{
replyInThread: _t("action|reply_in_thread"),
},
{
b: (sub) => <b>{sub}</b>,
},
)}
</p>
</>
);
}
return (
<div className="mx_ThreadPanel_empty">
<div className="mx_ThreadPanel_largeIcon" />
<h2>{_t("threads|empty_heading")}</h2>
{body}
</div> </div>
); );
}; };
@@ -268,11 +207,7 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
<BaseCard <BaseCard
hideHeaderButtons hideHeaderButtons
header={ header={
<ThreadPanelHeader hasThreads && <ThreadPanelHeader filterOption={filterOption} setFilterOption={setFilterOption} />
filterOption={filterOption}
setFilterOption={setFilterOption}
empty={!hasThreads}
/>
} }
id="thread-panel" id="thread-panel"
className="mx_ThreadPanel" className="mx_ThreadPanel"
@@ -295,10 +230,12 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
timelineSet={timelineSet} timelineSet={timelineSet}
showUrlPreview={false} // No URL previews at the threads list level showUrlPreview={false} // No URL previews at the threads list level
empty={ empty={
<EmptyThread <EmptyState
hasThreads={hasThreads} Icon={ThreadsIcon}
filterOption={filterOption} title={_t("threads|empty_title")}
showAllThreadsCallback={() => setFilterOption(ThreadFilterType.All)} description={_t("threads|empty_description", {
replyInThread: _t("action|reply_in_thread"),
})}
/> />
} }
alwaysShowTimestamps={true} alwaysShowTimestamps={true}
@@ -0,0 +1,42 @@
/*
Copyright 2024 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ComponentType } from "react";
import { Text } from "@vector-im/compound-web";
import { Flex } from "../../utils/Flex";
interface Props {
Icon: ComponentType<React.SVGAttributes<SVGElement>>;
title: string;
description: string;
}
const EmptyState: React.FC<Props> = ({ Icon, title, description }) => {
return (
<Flex className="mx_EmptyState" direction="column" gap="var(--cpd-space-4x)" align="center" justify="center">
<Icon width="32px" height="32px" />
<Text size="lg" weight="semibold">
{title}
</Text>
<Text size="md" weight="regular">
{description}
</Text>
</Flex>
);
};
export default EmptyState;
-5
View File
@@ -3097,15 +3097,10 @@
"one": "%(count)s odpověď", "one": "%(count)s odpověď",
"other": "%(count)s odpovědí" "other": "%(count)s odpovědí"
}, },
"empty_explainer": "Vlákna pomáhají udržovat konverzace k tématu a snadno je sledovat.",
"empty_has_threads_tip": "Odpovědět na probíhající vlákno nebo použít \"%(replyInThread)s\", když najedete na zprávu a začnete novou.",
"empty_heading": "Udržujte diskuse organizované pomocí vláken",
"empty_tip": "<b>Tip:</b> Použijte \"%(replyInThread)s\" při najetí na zprávu.",
"error_start_thread_existing_relation": "Nelze založit vlákno ve vlákně", "error_start_thread_existing_relation": "Nelze založit vlákno ve vlákně",
"my_threads": "Moje vlákna", "my_threads": "Moje vlákna",
"my_threads_description": "Zobrazit všechna vlákna, kterých jste se zúčastnili", "my_threads_description": "Zobrazit všechna vlákna, kterých jste se zúčastnili",
"open_thread": "Otevřít vlákno", "open_thread": "Otevřít vlákno",
"show_all_threads": "Zobrazit všechna vlákna",
"show_thread_filter": "Zobrazit:" "show_thread_filter": "Zobrazit:"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -3073,15 +3073,10 @@
"one": "%(count)s Antwort", "one": "%(count)s Antwort",
"other": "%(count)s Antworten" "other": "%(count)s Antworten"
}, },
"empty_explainer": "Threads helfen dabei, dass deine Konversationen beim Thema und leicht nachverfolgbar bleiben.",
"empty_has_threads_tip": "Antworte auf einen Thread oder klicke bei einer Nachricht auf „%(replyInThread)s“, um einen Thread zu starten.",
"empty_heading": "Organisiere Diskussionen mit Threads",
"empty_tip": "<b>Tipp:</b> Nutze “%(replyInThread)s” beim Schweben über eine Nachricht.",
"error_start_thread_existing_relation": "Du kannst keinen Thread in einem Thread starten", "error_start_thread_existing_relation": "Du kannst keinen Thread in einem Thread starten",
"my_threads": "Meine Threads", "my_threads": "Meine Threads",
"my_threads_description": "Zeigt alle Threads, an denen du teilgenommen hast", "my_threads_description": "Zeigt alle Threads, an denen du teilgenommen hast",
"open_thread": "Thread anzeigen", "open_thread": "Thread anzeigen",
"show_all_threads": "Alle Threads anzeigen",
"show_thread_filter": "Zeige:" "show_thread_filter": "Zeige:"
}, },
"time": { "time": {
-4
View File
@@ -2441,14 +2441,10 @@
"one": "%(count)s απάντηση", "one": "%(count)s απάντηση",
"other": "%(count)s απαντήσεις" "other": "%(count)s απαντήσεις"
}, },
"empty_explainer": "Τα νήματα σας βοηθούν να οργανώνετε και να παρακολουθείτε καλύτερα τις συνομιλίες σας.",
"empty_has_threads_tip": "Απαντήστε σε ένα νήμα εκτέλεσης που βρίσκεται σε εξέλιξη ή χρησιμοποιήστε το \"%(replyInThread)s\" όταν τοποθετείτε το δείκτη του ποντικιού πάνω από ένα μήνυμα για να ξεκινήσετε ένα νέο.",
"empty_heading": "Διατηρήστε τις συζητήσεις οργανωμένες με νήματα",
"error_start_thread_existing_relation": "Δεν είναι δυνατή η δημιουργία νήματος από ένα συμβάν με μια υπάρχουσα σχέση", "error_start_thread_existing_relation": "Δεν είναι δυνατή η δημιουργία νήματος από ένα συμβάν με μια υπάρχουσα σχέση",
"my_threads": "Τα νήματα μου", "my_threads": "Τα νήματα μου",
"my_threads_description": "Εμφανίζει όλα τα νήματα στα οποία έχετε συμμετάσχει", "my_threads_description": "Εμφανίζει όλα τα νήματα στα οποία έχετε συμμετάσχει",
"open_thread": "Άνοιγμα νήματος", "open_thread": "Άνοιγμα νήματος",
"show_all_threads": "Εμφάνιση όλων των νημάτων",
"show_thread_filter": "Εμφάνισε:" "show_thread_filter": "Εμφάνισε:"
}, },
"time": { "time": {
+2 -5
View File
@@ -3193,16 +3193,13 @@
"one": "%(count)s reply", "one": "%(count)s reply",
"other": "%(count)s replies" "other": "%(count)s replies"
}, },
"empty_explainer": "Threads help keep your conversations on-topic and easy to track.", "empty_description": "Use “%(replyInThread)s” when hovering over a message.",
"empty_has_threads_tip": "Reply to an ongoing thread or use “%(replyInThread)s” when hovering over a message to start a new one.", "empty_title": "Threads help keep your conversations on-topic and easy to track.",
"empty_heading": "Keep discussions organised with threads",
"empty_tip": "<b>Tip:</b> Use “%(replyInThread)s” when hovering over a message.",
"error_start_thread_existing_relation": "Can't create a thread from an event with an existing relation", "error_start_thread_existing_relation": "Can't create a thread from an event with an existing relation",
"mark_all_read": "Mark all as read", "mark_all_read": "Mark all as read",
"my_threads": "My threads", "my_threads": "My threads",
"my_threads_description": "Shows all threads you've participated in", "my_threads_description": "Shows all threads you've participated in",
"open_thread": "Open thread", "open_thread": "Open thread",
"show_all_threads": "Show all threads",
"show_thread_filter": "Show:" "show_thread_filter": "Show:"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -2822,15 +2822,10 @@
"one": "%(count)s respuesta", "one": "%(count)s respuesta",
"other": "%(count)s respuestas" "other": "%(count)s respuestas"
}, },
"empty_explainer": "Los hilos ayudan a mantener tus conversaciones centradas y a que sean fáciles de seguir.",
"empty_has_threads_tip": "Responde a un hilo en curso o usa «%(replyInThread)s» al pasar el ratón por encima de un mensaje para iniciar uno nuevo.",
"empty_heading": "Organiza los temas de conversación en hilos",
"empty_tip": "<b>Consejo:</b> Usa «%(replyInThread)s» mientras pasas el ratón sobre un mensaje.",
"error_start_thread_existing_relation": "No ha sido posible crear un hilo a partir de un evento con una relación existente", "error_start_thread_existing_relation": "No ha sido posible crear un hilo a partir de un evento con una relación existente",
"my_threads": "Mis hilos", "my_threads": "Mis hilos",
"my_threads_description": "Ver todos los hilos en los que has participado", "my_threads_description": "Ver todos los hilos en los que has participado",
"open_thread": "Abrir hilo", "open_thread": "Abrir hilo",
"show_all_threads": "Ver todos los hilos",
"show_thread_filter": "Mostrar:" "show_thread_filter": "Mostrar:"
}, },
"time": { "time": {
-5
View File
@@ -3044,15 +3044,10 @@
"one": "%(count)s vastus", "one": "%(count)s vastus",
"other": "%(count)s vastust" "other": "%(count)s vastust"
}, },
"empty_explainer": "Jutulõngad aitavad hoida vestlused teemakohastena ning mugavalt loetavatena.",
"empty_has_threads_tip": "Vasta jätkuvas jutulõngas või uue jutulõnga loomiseks kasuta „%(replyInThread)s“ valikut, mida kuvatakse hiire liigutamisel sõnumi kohal.",
"empty_heading": "Halda vestlusi jutulõngadena",
"empty_tip": "<b>Soovitus:</b> Sõnumi kohal avanevast valikust kasuta „%(replyInThread)s“ võimalust.",
"error_start_thread_existing_relation": "Jutulõnga ei saa luua sõnumist, mis juba on jutulõnga osa", "error_start_thread_existing_relation": "Jutulõnga ei saa luua sõnumist, mis juba on jutulõnga osa",
"my_threads": "Minu jutulõngad", "my_threads": "Minu jutulõngad",
"my_threads_description": "Näitab kõiki jutulõngasid, kus sa oled osalenud", "my_threads_description": "Näitab kõiki jutulõngasid, kus sa oled osalenud",
"open_thread": "Ava jutulõng", "open_thread": "Ava jutulõng",
"show_all_threads": "Näita kõiki jutulõngasid",
"show_thread_filter": "Näita:" "show_thread_filter": "Näita:"
}, },
"time": { "time": {
-3
View File
@@ -2695,12 +2695,9 @@
"one": "%(count)s vastaus", "one": "%(count)s vastaus",
"other": "%(count)s vastausta" "other": "%(count)s vastausta"
}, },
"empty_explainer": "Ketjut auttavat pitämään keskustelut asiayhteyteen sopivina ja helposti seurattavina.",
"empty_heading": "Pidä keskustelut järjestyksessä ketjuissa",
"my_threads": "Omat ketjut", "my_threads": "Omat ketjut",
"my_threads_description": "Näyttää kaikki ketjut, joissa olet ollut osallinen", "my_threads_description": "Näyttää kaikki ketjut, joissa olet ollut osallinen",
"open_thread": "Avaa ketju", "open_thread": "Avaa ketju",
"show_all_threads": "Näytä kaikki ketjut",
"show_thread_filter": "Näytä:" "show_thread_filter": "Näytä:"
}, },
"time": { "time": {
-5
View File
@@ -3125,16 +3125,11 @@
"one": "%(count)s réponse", "one": "%(count)s réponse",
"other": "%(count)s réponses" "other": "%(count)s réponses"
}, },
"empty_explainer": "Les fils de discussion vous permettent de recentrer vos conversations et de les rendre facile à suivre.",
"empty_has_threads_tip": "Répondez à un fil de discussion en cours ou utilisez \"%(replyInThread)s\" lorsque vous passez la souris sur un message pour en commencer un nouveau.",
"empty_heading": "Garde les discussions organisées à l’aide de fils de discussion",
"empty_tip": "<b>Conseil :</b> Utilisez « %(replyInThread)s » en survolant un message.",
"error_start_thread_existing_relation": "Impossible de créer un fil de discussion à partir d’un événement avec une relation existante", "error_start_thread_existing_relation": "Impossible de créer un fil de discussion à partir d’un événement avec une relation existante",
"mark_all_read": "Tout marquer comme lu", "mark_all_read": "Tout marquer comme lu",
"my_threads": "Mes fils de discussion", "my_threads": "Mes fils de discussion",
"my_threads_description": "Affiche tous les fils de discussion auxquels vous avez participé", "my_threads_description": "Affiche tous les fils de discussion auxquels vous avez participé",
"open_thread": "Ouvrir le fil de discussion", "open_thread": "Ouvrir le fil de discussion",
"show_all_threads": "Afficher tous les fils de discussion",
"show_thread_filter": "Affiche :" "show_thread_filter": "Affiche :"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -2598,15 +2598,10 @@
"one": "%(count)s resposta", "one": "%(count)s resposta",
"other": "%(count)s respostas" "other": "%(count)s respostas"
}, },
"empty_explainer": "Os fíos axúdanche a manter as conversas no tema e facilitan o seguimento.",
"empty_has_threads_tip": "Responde a unha conversa en curso ou usa \"%(replyInThread)s\" cando pasas por enriba dunha mensaxe co rato para iniciar unha nova.",
"empty_heading": "Manter as conversas organizadas con fíos",
"empty_tip": "<b>Truco:</b> Usa \"%(replyInThread)s\" ao poñerte enriba dunha mensaxe.",
"error_start_thread_existing_relation": "Non se pode crear un tema con unha relación existente desde un evento", "error_start_thread_existing_relation": "Non se pode crear un tema con unha relación existente desde un evento",
"my_threads": "As miñas conversas", "my_threads": "As miñas conversas",
"my_threads_description": "Mostra tódalas conversas nas que participaches", "my_threads_description": "Mostra tódalas conversas nas que participaches",
"open_thread": "Abrir fío", "open_thread": "Abrir fío",
"show_all_threads": "Mostra tódolos temas",
"show_thread_filter": "Mostrar:" "show_thread_filter": "Mostrar:"
}, },
"time": { "time": {
-5
View File
@@ -2076,15 +2076,10 @@
"threads": { "threads": {
"all_threads": "כל הקישורים", "all_threads": "כל הקישורים",
"all_threads_description": "הצג את כל הקישורים מחדר זה", "all_threads_description": "הצג את כל הקישורים מחדר זה",
"empty_explainer": "שרשורים עוזרים לשמור על השיחות שלכם בנושא וקל למעקב.",
"empty_has_threads_tip": "השיבו לשרשור מתמשך או השתמשו ב-\"%(replyInThread)s\" כשאתם מרחפים מעל הודעה כדי להתחיל הודעה חדשה.",
"empty_heading": "שימרו על דיונים מאורגנים בשרשורים",
"empty_tip": "<b>טיפ:</b> השתמש ב-\"%(replyInThread)s\" כשאתם מרחפים מעל הודעה.",
"error_start_thread_existing_relation": "לא ניתן ליצור שרשור מאירוע עם קשר קיים", "error_start_thread_existing_relation": "לא ניתן ליצור שרשור מאירוע עם קשר קיים",
"my_threads": "הקישורים שלי", "my_threads": "הקישורים שלי",
"my_threads_description": "הצג את כל השרשורים שאתם משתתפים בהם", "my_threads_description": "הצג את כל השרשורים שאתם משתתפים בהם",
"open_thread": "פתיחת שרשור", "open_thread": "פתיחת שרשור",
"show_all_threads": "הצג את כל השרשורים",
"show_thread_filter": "הצג:" "show_thread_filter": "הצג:"
}, },
"time": { "time": {
-5
View File
@@ -3012,15 +3012,10 @@
"one": "%(count)s válasz", "one": "%(count)s válasz",
"other": "%(count)s válasz" "other": "%(count)s válasz"
}, },
"empty_explainer": "Az üzenetszálak segítenek a különböző témájú beszélgetések figyelemmel kísérésében.",
"empty_has_threads_tip": "Válaszoljon egy meglévő üzenetszálban, vagy új üzenetszál indításához használja a „%(replyInThread)s” lehetőséget az üzenet sarkában megjelenő menüben.",
"empty_heading": "Beszélgetések üzenetszálakba rendezése",
"empty_tip": "<b>Tipp:</b> Használja a „%(replyInThread)s” lehetőséget a szöveg fölé navigálva.",
"error_start_thread_existing_relation": "Nem lehet üzenetszálat indítani olyan eseményről ami már rendelkezik kapcsolattal", "error_start_thread_existing_relation": "Nem lehet üzenetszálat indítani olyan eseményről ami már rendelkezik kapcsolattal",
"my_threads": "Saját üzenetszálak", "my_threads": "Saját üzenetszálak",
"my_threads_description": "Minden üzenetszál megjelenítése, amelyben részt vesz", "my_threads_description": "Minden üzenetszál megjelenítése, amelyben részt vesz",
"open_thread": "Üzenetszál megnyitása", "open_thread": "Üzenetszál megnyitása",
"show_all_threads": "Minden üzenetszál megjelenítése",
"show_thread_filter": "Megjelenítés:" "show_thread_filter": "Megjelenítés:"
}, },
"time": { "time": {
-5
View File
@@ -3046,15 +3046,10 @@
"one": "%(count)s balasan", "one": "%(count)s balasan",
"other": "%(count)s balasan" "other": "%(count)s balasan"
}, },
"empty_explainer": "Utasan membantu membuat obrolan sesuai topik dan mudah untuk dilacak.",
"empty_has_threads_tip": "Balas ke utasan yang sedang terjadi atau gunakan “%(replyInThread)s” ketika kursor diletakkan pada pesan untuk memulai yang baru.",
"empty_heading": "Buat diskusi tetap teratur dengan utasan",
"empty_tip": "<b>Tip:</b> Gunakan “%(replyInThread)s” ketika kursor di atas pesan.",
"error_start_thread_existing_relation": "Tidak dapat membuat utasan dari sebuah peristiwa dengan relasi yang sudah ada", "error_start_thread_existing_relation": "Tidak dapat membuat utasan dari sebuah peristiwa dengan relasi yang sudah ada",
"my_threads": "Utasan saya", "my_threads": "Utasan saya",
"my_threads_description": "Menampilkan semua utasan yang Anda berpartisipasi", "my_threads_description": "Menampilkan semua utasan yang Anda berpartisipasi",
"open_thread": "Buka utasan", "open_thread": "Buka utasan",
"show_all_threads": "Tampilkan semua utasan",
"show_thread_filter": "Tampilkan:" "show_thread_filter": "Tampilkan:"
}, },
"time": { "time": {
-3
View File
@@ -2505,12 +2505,9 @@
"one": "%(count)s svar", "one": "%(count)s svar",
"other": "%(count)s svör" "other": "%(count)s svör"
}, },
"empty_explainer": "Spjallþræðir hjálpa til við að halda samræðum við efnið og gerir auðveldara að rekja þær.",
"empty_heading": "Haltu umræðum skipulögðum með spjallþráðum",
"my_threads": "Spjallþræðirnir mínir", "my_threads": "Spjallþræðirnir mínir",
"my_threads_description": "Birtir alla spjallþræði sem þú hefur tekið þátt í", "my_threads_description": "Birtir alla spjallþræði sem þú hefur tekið þátt í",
"open_thread": "Opna spjallþráð", "open_thread": "Opna spjallþráð",
"show_all_threads": "Birta alla spjallþræði",
"show_thread_filter": "Sýna:" "show_thread_filter": "Sýna:"
}, },
"time": { "time": {
-5
View File
@@ -3090,15 +3090,10 @@
"one": "%(count)s risposta", "one": "%(count)s risposta",
"other": "%(count)s risposte" "other": "%(count)s risposte"
}, },
"empty_explainer": "Le conversazioni ti aiutano a tenere le tue discussioni in tema e rintracciabili.",
"empty_has_threads_tip": "Rispondi ad una conversazione in corso o usa \"%(replyInThread)s\" passando sopra ad un messaggio per iniziarne una nuova.",
"empty_heading": "Tieni le discussioni organizzate in conversazioni",
"empty_tip": "<b>Consiglio:</b> usa \"%(replyInThread)s\" passando sopra un messaggio.",
"error_start_thread_existing_relation": "Impossibile creare una conversazione da un evento con una relazione esistente", "error_start_thread_existing_relation": "Impossibile creare una conversazione da un evento con una relazione esistente",
"my_threads": "Le mie conversazioni", "my_threads": "Le mie conversazioni",
"my_threads_description": "Mostra tutte le conversazioni a cui hai partecipato", "my_threads_description": "Mostra tutte le conversazioni a cui hai partecipato",
"open_thread": "Apri conversazione", "open_thread": "Apri conversazione",
"show_all_threads": "Mostra tutte le conversazioni",
"show_thread_filter": "Mostra:" "show_thread_filter": "Mostra:"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -2827,15 +2827,10 @@
"other": "%(count)s件の返信", "other": "%(count)s件の返信",
"one": "%(count)s件の返信" "one": "%(count)s件の返信"
}, },
"empty_explainer": "スレッド機能を使うと、会話のテーマを維持したり、会話を簡単に追跡したりすることができます。",
"empty_has_threads_tip": "既存のスレッドに返信するか、メッセージの「%(replyInThread)s」機能を使用すると新しいスレッドを開始できます。",
"empty_heading": "スレッド機能を使って、会話をまとめましょう",
"empty_tip": "<b>ヒント:</b>メッセージの「%(replyInThread)s」機能を使用すると新しいスレッドを開始できます。",
"error_start_thread_existing_relation": "既存の関係のあるイベントからスレッドを作成することはできません", "error_start_thread_existing_relation": "既存の関係のあるイベントからスレッドを作成することはできません",
"my_threads": "自分のスレッド", "my_threads": "自分のスレッド",
"my_threads_description": "参加している全スレッドを表示", "my_threads_description": "参加している全スレッドを表示",
"open_thread": "スレッドを開く", "open_thread": "スレッドを開く",
"show_all_threads": "全てのスレッドを表示",
"show_thread_filter": "表示:" "show_thread_filter": "表示:"
}, },
"time": { "time": {
-5
View File
@@ -2457,15 +2457,10 @@
"one": "%(count)s ຕອບກັບ", "one": "%(count)s ຕອບກັບ",
"other": "%(count)s ຕອບກັບ" "other": "%(count)s ຕອບກັບ"
}, },
"empty_explainer": "ກະທູ້ຊ່ວຍໃຫ້ການສົນທະນາຂອງທ່ານຢູ່ໃນຫົວຂໍ້ ແລະ ງ່າຍຕໍ່ການຕິດຕາມ.",
"empty_has_threads_tip": "ຕອບກັບຫາກະທູ້ທີ່ກຳລັງດຳເນີນ ຫຼືໃຊ້ ຢູ່“%(replyInThread)s” ເມື່ອເລື່ອນໃສ່ຂໍ້ຄວາມເພື່ອເລີ່ມຕົ້ນອັນໃໝ່.",
"empty_heading": "ຮັກສາການສົນທະນາທີ່ມີການຈັດລະບຽບ",
"empty_tip": "<b>ເຄັດລັບ:</b> ໃຊ້ “%(replyInThread)s” ເມື່ອເລື່ອນໃສ່ຂໍ້ຄວາມ.",
"error_start_thread_existing_relation": "ບໍ່ສາມາດສ້າງກະທູ້ຈາກເຫດການທີ່ມີຄວາມສໍາພັນທີ່ມີຢູ່ແລ້ວ", "error_start_thread_existing_relation": "ບໍ່ສາມາດສ້າງກະທູ້ຈາກເຫດການທີ່ມີຄວາມສໍາພັນທີ່ມີຢູ່ແລ້ວ",
"my_threads": "ກະທູ້ຂອງຂ້ອຍ", "my_threads": "ກະທູ້ຂອງຂ້ອຍ",
"my_threads_description": "ສະແດງຫົວຂໍ້ທັງໝົດທີ່ທ່ານໄດ້ເຂົ້າຮ່ວມ", "my_threads_description": "ສະແດງຫົວຂໍ້ທັງໝົດທີ່ທ່ານໄດ້ເຂົ້າຮ່ວມ",
"open_thread": "ເປີດກະທູ້", "open_thread": "ເປີດກະທູ້",
"show_all_threads": "ສະແດງຫົວຂໍ້ທັງໝົດ",
"show_thread_filter": "ສະແດງ:" "show_thread_filter": "ສະແດງ:"
}, },
"time": { "time": {
-5
View File
@@ -2620,15 +2620,10 @@
"one": "%(count)s reactie", "one": "%(count)s reactie",
"other": "%(count)s reacties" "other": "%(count)s reacties"
}, },
"empty_explainer": "Threads helpen jou gesprekken on-topic te houden en gemakkelijk bij te houden.",
"empty_has_threads_tip": "Reageer op een lopende thread of gebruik \"%(replyInThread)s\" wanneer je de muisaanwijzer op een bericht plaatst om een nieuwe te starten.",
"empty_heading": "Houd threads georganiseerd",
"empty_tip": "<b>Tip:</b> Gebruik “%(replyInThread)s” met de muiscursor boven een bericht.",
"error_start_thread_existing_relation": "Kan geen discussie maken van een gebeurtenis met een bestaande relatie", "error_start_thread_existing_relation": "Kan geen discussie maken van een gebeurtenis met een bestaande relatie",
"my_threads": "Mijn discussies", "my_threads": "Mijn discussies",
"my_threads_description": "Toon alle threads waarin je hebt bijgedragen", "my_threads_description": "Toon alle threads waarin je hebt bijgedragen",
"open_thread": "Open discussie", "open_thread": "Open discussie",
"show_all_threads": "Threads weergeven",
"show_thread_filter": "Toon:" "show_thread_filter": "Toon:"
}, },
"time": { "time": {
-5
View File
@@ -3197,16 +3197,11 @@
"one": "%(count)s odpowiedź", "one": "%(count)s odpowiedź",
"other": "%(count)s odpowiedzi" "other": "%(count)s odpowiedzi"
}, },
"empty_explainer": "Dzięki wątkom Twoje rozmowy są zorganizowane i łatwe do śledzenia.",
"empty_has_threads_tip": "Odpowiedz do trwającego już wątku lub użyj “%(replyInThread)s” najeżdżając na wiadomość, aby rozpocząć nową.",
"empty_heading": "Organizuj dyskusje za pomocą wątków",
"empty_tip": "<b>Tip:</b> Użyj “%(replyInThread)s” najeżdżając na wiadomość.",
"error_start_thread_existing_relation": "Nie można utworzyć wątku z wydarzenia z istniejącą relacją", "error_start_thread_existing_relation": "Nie można utworzyć wątku z wydarzenia z istniejącą relacją",
"mark_all_read": "Oznacz wszystkie jako przeczytane", "mark_all_read": "Oznacz wszystkie jako przeczytane",
"my_threads": "Moje wątki", "my_threads": "Moje wątki",
"my_threads_description": "Pokazuje wszystkie wątki, w których brałeś udział", "my_threads_description": "Pokazuje wszystkie wątki, w których brałeś udział",
"open_thread": "Otwórz wątek", "open_thread": "Otwórz wątek",
"show_all_threads": "Pokaż wszystkie wątki",
"show_thread_filter": "Pokaż:" "show_thread_filter": "Pokaż:"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -3074,15 +3074,10 @@
"one": "%(count)s ответ", "one": "%(count)s ответ",
"other": "%(count)s ответов" "other": "%(count)s ответов"
}, },
"empty_explainer": "Обсуждения помогают поддерживать и легко отслеживать тематику бесед.",
"empty_has_threads_tip": "Ответьте в текущее обсуждение или создайте новое, наведя курсор на сообщение и нажав «%(replyInThread)s».",
"empty_heading": "Организуйте обсуждения с помощью обсуждений",
"empty_tip": "<b>Совет:</b> Используйте “%(replyInThread)s” при наведении курсора на сообщение.",
"error_start_thread_existing_relation": "Невозможно создать обсуждение из события с существующей связью", "error_start_thread_existing_relation": "Невозможно создать обсуждение из события с существующей связью",
"my_threads": "Мои обсуждения", "my_threads": "Мои обсуждения",
"my_threads_description": "Показывает все обсуждения, в которых вы принимали участие", "my_threads_description": "Показывает все обсуждения, в которых вы принимали участие",
"open_thread": "Открыть ветку", "open_thread": "Открыть ветку",
"show_all_threads": "Показать все обсуждения",
"show_thread_filter": "Показать:" "show_thread_filter": "Показать:"
}, },
"time": { "time": {
-5
View File
@@ -3077,15 +3077,10 @@
"one": "%(count)s odpoveď", "one": "%(count)s odpoveď",
"other": "%(count)s odpovedí" "other": "%(count)s odpovedí"
}, },
"empty_explainer": "Vlákna pomáhajú udržiavať konverzácie v téme a uľahčujú ich sledovanie.",
"empty_has_threads_tip": "Odpovedzte na prebiehajúce vlákno alebo použite \"%(replyInThread)s\", keď prejdete nad správu a začnete novú.",
"empty_heading": "Udržujte diskusie organizované pomocou vlákien",
"empty_tip": "<b>Tip:</b> Použite položku “%(replyInThread)s”, keď prejdete ponad správu.",
"error_start_thread_existing_relation": "Nie je možné vytvoriť vlákno z udalosti s existujúcim vzťahom", "error_start_thread_existing_relation": "Nie je možné vytvoriť vlákno z udalosti s existujúcim vzťahom",
"my_threads": "Moje vlákna", "my_threads": "Moje vlákna",
"my_threads_description": "Zobrazí všetky vlákna, v ktorých ste sa zúčastnili", "my_threads_description": "Zobrazí všetky vlákna, v ktorých ste sa zúčastnili",
"open_thread": "Otvoriť vlákno", "open_thread": "Otvoriť vlákno",
"show_all_threads": "Zobraziť všetky vlákna",
"show_thread_filter": "Zobraziť:" "show_thread_filter": "Zobraziť:"
}, },
"time": { "time": {
-5
View File
@@ -2894,15 +2894,10 @@
"one": "%(count)s përgjigje", "one": "%(count)s përgjigje",
"other": "%(count)s përgjigje" "other": "%(count)s përgjigje"
}, },
"empty_explainer": "Rrjedhat ndihmojnë që të mbahen bisedat tuaja brenda temës dhe të ndiqen kollaj.",
"empty_has_threads_tip": "Përgjigjuni te një rrjedhë në zhvillim e sipër, ose përdorni “%(replyInThread)s”, kur kalohet kursori sipër një mesazhi për të filluar një të re.",
"empty_heading": "Mbajini diskutimet të sistemuara në rrjedha",
"empty_tip": "<b>Ndihmëz:</b> Përdorni “%(replyInThread)s”, teksa kaloni kursorin sipër një mesazhi.",
"error_start_thread_existing_relation": "S’mund të krijohet një rrjedhë prej një akti me një marrëdhënie ekzistuese", "error_start_thread_existing_relation": "S’mund të krijohet një rrjedhë prej një akti me një marrëdhënie ekzistuese",
"my_threads": "Rrjedhat e mia", "my_threads": "Rrjedhat e mia",
"my_threads_description": "Shfaq krejt rrjedhat ku keni marrë pjesë", "my_threads_description": "Shfaq krejt rrjedhat ku keni marrë pjesë",
"open_thread": "Hape rrjedhën", "open_thread": "Hape rrjedhën",
"show_all_threads": "Shfaqi krejt rrjedhat",
"show_thread_filter": "Shfaq:" "show_thread_filter": "Shfaq:"
}, },
"time": { "time": {
-5
View File
@@ -3089,15 +3089,10 @@
"one": "%(count)s svar", "one": "%(count)s svar",
"other": "%(count)s svar" "other": "%(count)s svar"
}, },
"empty_explainer": "Trådar underlättar för att hålla konversationer till ämnet och gör dem lättare att följa.",
"empty_has_threads_tip": "Svara i en pågående tråd eller använd \"%(replyInThread)s\" när du håller över ett meddelande för att starta en ny tråd.",
"empty_heading": "Håll diskussioner organiserade med trådar",
"empty_tip": "<b>Tips:</b> Välj \"%(replyInThread)s\" när du håller över ett meddelande.",
"error_start_thread_existing_relation": "Kan inte skapa tråd från en händelse med en existerande relation", "error_start_thread_existing_relation": "Kan inte skapa tråd från en händelse med en existerande relation",
"my_threads": "Mina trådar", "my_threads": "Mina trådar",
"my_threads_description": "Visar alla trådar du har medverkat i", "my_threads_description": "Visar alla trådar du har medverkat i",
"open_thread": "Öppna tråd", "open_thread": "Öppna tråd",
"show_all_threads": "Visa alla trådar",
"show_thread_filter": "Visa:" "show_thread_filter": "Visa:"
}, },
"threads_activity_centre": { "threads_activity_centre": {
-5
View File
@@ -3009,15 +3009,10 @@
"one": "%(count)s відповідь", "one": "%(count)s відповідь",
"other": "%(count)s відповідей" "other": "%(count)s відповідей"
}, },
"empty_explainer": "Гілки допомагають підтримувати розмови за темою та за ними легко стежити.",
"empty_has_threads_tip": "Дайте відповідь у наявну гілку, або створіть нову, навівши курсор на повідомлення й натиснувши «%(replyInThread)s».",
"empty_heading": "Упорядкуйте обговорення за допомогою гілок",
"empty_tip": "<b>Порада:</b> Використовуйте «%(replyInThread)s» навівши вказівник на повідомлення.",
"error_start_thread_existing_relation": "Неможливо створити гілку з події з наявним відношенням", "error_start_thread_existing_relation": "Неможливо створити гілку з події з наявним відношенням",
"my_threads": "Мої гілки", "my_threads": "Мої гілки",
"my_threads_description": "Показує всі гілки, де ви брали участь", "my_threads_description": "Показує всі гілки, де ви брали участь",
"open_thread": "Відкрити гілку", "open_thread": "Відкрити гілку",
"show_all_threads": "Показати всі гілки",
"show_thread_filter": "Показати:" "show_thread_filter": "Показати:"
}, },
"time": { "time": {
-2
View File
@@ -2768,10 +2768,8 @@
"one": "%(count)s trả lời", "one": "%(count)s trả lời",
"other": "%(count)s trả lời" "other": "%(count)s trả lời"
}, },
"empty_heading": "Giữ các cuộc thảo luận được tổ chức với các chủ đề này",
"my_threads": "Các chủ đề của tôi", "my_threads": "Các chủ đề của tôi",
"my_threads_description": "Hiển thị tất cả các chủ đề bạn đã tham gia", "my_threads_description": "Hiển thị tất cả các chủ đề bạn đã tham gia",
"show_all_threads": "Hiển thị tất cả chủ đề",
"show_thread_filter": "Hiển thị:" "show_thread_filter": "Hiển thị:"
}, },
"time": { "time": {
-5
View File
@@ -2752,15 +2752,10 @@
"one": "%(count)s 条回复", "one": "%(count)s 条回复",
"other": "%(count)s 条回复" "other": "%(count)s 条回复"
}, },
"empty_explainer": "消息列帮助保持你的对话切题并易于追踪。",
"empty_has_threads_tip": "回复进行中的消息列或当悬停在消息上时使用%(replyInThread)s来发起新的消息列。",
"empty_heading": "用消息列使讨论井然有序",
"empty_tip": "<b>实用提示:</b>悬停在消息上时使用“%(replyInThread)s”。",
"error_start_thread_existing_relation": "无法从既有关系的事件创建消息列", "error_start_thread_existing_relation": "无法从既有关系的事件创建消息列",
"my_threads": "我的消息列", "my_threads": "我的消息列",
"my_threads_description": "显示您参与的所有消息列", "my_threads_description": "显示您参与的所有消息列",
"open_thread": "打开消息列", "open_thread": "打开消息列",
"show_all_threads": "显示所有消息列",
"show_thread_filter": "显示:" "show_thread_filter": "显示:"
}, },
"time": { "time": {
-5
View File
@@ -3004,15 +3004,10 @@
"one": "%(count)s 回覆", "one": "%(count)s 回覆",
"other": "%(count)s 回覆" "other": "%(count)s 回覆"
}, },
"empty_explainer": "「討論串」功能可以協助您的對話不離題且易於追蹤。",
"empty_has_threads_tip": "將滑鼠游標停留在訊息上來開始新的討論串時,回覆正在進行的討論串或使用「%(replyInThread)s」。",
"empty_heading": "使用「討論串」功能,讓討論保持有條不紊",
"empty_tip": "<b>秘訣:</b>在滑鼠游標停於訊息上時使用「%(replyInThread)s」。",
"error_start_thread_existing_relation": "無法從討論串既有的關係建立活動", "error_start_thread_existing_relation": "無法從討論串既有的關係建立活動",
"my_threads": "我的討論串", "my_threads": "我的討論串",
"my_threads_description": "顯示您參與的所有討論串", "my_threads_description": "顯示您參與的所有討論串",
"open_thread": "開啟討論串", "open_thread": "開啟討論串",
"show_all_threads": "顯示所有討論串",
"show_thread_filter": "顯示:" "show_thread_filter": "顯示:"
}, },
"time": { "time": {
@@ -0,0 +1,58 @@
/*
Copyright 2024 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import { EventTimelineSet, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
import { screen, render, waitFor } from "@testing-library/react";
import { mocked } from "jest-mock";
import FilePanel from "../../../src/components/structures/FilePanel";
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
import { stubClient } from "../../test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
jest.mock("matrix-js-sdk/src/matrix", () => ({
...jest.requireActual("matrix-js-sdk/src/matrix"),
TimelineWindow: jest.fn().mockReturnValue({
load: jest.fn().mockResolvedValue(null),
getEvents: jest.fn().mockReturnValue([]),
canPaginate: jest.fn().mockReturnValue(false),
}),
}));
describe("FilePanel", () => {
beforeEach(() => {
stubClient();
});
it("renders empty state", async () => {
const cli = MatrixClientPeg.safeGet();
const room = new Room("!room:server", cli, cli.getSafeUserId(), {
pendingEventOrdering: PendingEventOrdering.Detached,
});
const timelineSet = new EventTimelineSet(room);
room.getOrCreateFilteredTimelineSet = jest.fn().mockReturnValue(timelineSet);
mocked(cli.getRoom).mockReturnValue(room);
const { asFragment } = render(
<FilePanel roomId={room.roomId} onClose={jest.fn()} resizeNotifier={new ResizeNotifier()} />,
);
await waitFor(() => {
expect(screen.getByText("No files visible in this room")).toBeInTheDocument();
});
expect(asFragment()).toMatchSnapshot();
});
});
@@ -43,44 +43,21 @@ describe("ThreadPanel", () => {
describe("Header", () => { describe("Header", () => {
it("expect that All filter for ThreadPanelHeader properly renders Show: All threads", () => { it("expect that All filter for ThreadPanelHeader properly renders Show: All threads", () => {
const { asFragment } = render( const { asFragment } = render(
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.All} setFilterOption={() => undefined} />,
empty={false}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>,
); );
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
it("expect that My filter for ThreadPanelHeader properly renders Show: My threads", () => { it("expect that My filter for ThreadPanelHeader properly renders Show: My threads", () => {
const { asFragment } = render( const { asFragment } = render(
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.My} setFilterOption={() => undefined} />,
empty={false}
filterOption={ThreadFilterType.My}
setFilterOption={() => undefined}
/>,
);
expect(asFragment()).toMatchSnapshot();
});
it("matches snapshot when no threads", () => {
const { asFragment } = render(
<ThreadPanelHeader
empty={true}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>,
); );
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
it("expect that ThreadPanelHeader properly opens a context menu when clicked on the button", () => { it("expect that ThreadPanelHeader properly opens a context menu when clicked on the button", () => {
const { container } = render( const { container } = render(
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.All} setFilterOption={() => undefined} />,
empty={false}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>,
); );
const found = container.querySelector(".mx_ThreadPanel_dropdown"); const found = container.querySelector(".mx_ThreadPanel_dropdown");
expect(found).toBeTruthy(); expect(found).toBeTruthy();
@@ -91,11 +68,7 @@ describe("ThreadPanel", () => {
it("expect that ThreadPanelHeader has the correct option selected in the context menu", () => { it("expect that ThreadPanelHeader has the correct option selected in the context menu", () => {
const { container } = render( const { container } = render(
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.All} setFilterOption={() => undefined} />,
empty={false}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>,
); );
fireEvent.click(container.querySelector(".mx_ThreadPanel_dropdown")!); fireEvent.click(container.querySelector(".mx_ThreadPanel_dropdown")!);
const found = screen.queryAllByRole("menuitemradio"); const found = screen.queryAllByRole("menuitemradio");
@@ -118,11 +91,7 @@ describe("ThreadPanel", () => {
const { container } = render( const { container } = render(
<RoomContext.Provider value={roomContextObject}> <RoomContext.Provider value={roomContextObject}>
<MatrixClientContext.Provider value={mockClient}> <MatrixClientContext.Provider value={mockClient}>
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.All} setFilterOption={() => undefined} />
empty={false}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>
</MatrixClientContext.Provider> </MatrixClientContext.Provider>
</RoomContext.Provider>, </RoomContext.Provider>,
); );
@@ -136,11 +105,7 @@ describe("ThreadPanel", () => {
const mockClient = createTestClient(); const mockClient = createTestClient();
const { container } = render( const { container } = render(
<MatrixClientContext.Provider value={mockClient}> <MatrixClientContext.Provider value={mockClient}>
<ThreadPanelHeader <ThreadPanelHeader filterOption={ThreadFilterType.All} setFilterOption={() => undefined} />
empty={false}
filterOption={ThreadFilterType.All}
setFilterOption={() => undefined}
/>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
fireEvent.click(getByRole(container, "button", { name: "Mark all as read" })); fireEvent.click(getByRole(container, "button", { name: "Mark all as read" }));
@@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`FilePanel renders empty state 1`] = `
<DocumentFragment>
<div
class="mx_BaseCard mx_FilePanel"
>
<div
class="mx_BaseCard_header"
>
<div
class="mx_BaseCard_header_spacer"
/>
<button
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
</div>
<div
class="mx_RoomView_messagePanel mx_RoomView_messageListWrapper"
>
<div
class="mx_RoomView_empty"
>
<div
class="mx_Flex mx_EmptyState"
style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: center; --mx-flex-justify: center; --mx-flex-gap: var(--cpd-space-4x);"
>
<div
height="32px"
width="32px"
/>
<p
class="_typography_yh5dq_162 _font-body-lg-semibold_yh5dq_83"
>
No files visible in this room
</p>
<p
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
>
Attach files from chat or just drag and drop them anywhere in a room.
</p>
</div>
</div>
</div>
</div>
</DocumentFragment>
`;
@@ -95,17 +95,3 @@ exports[`ThreadPanel Header expect that ThreadPanelHeader has the correct option
</span> </span>
</div> </div>
`; `;
exports[`ThreadPanel Header matches snapshot when no threads 1`] = `
<DocumentFragment>
<div
class="mx_BaseCard_header_title"
>
<h4
class="mx_Heading_h4 mx_BaseCard_header_title_heading"
>
Threads
</h4>
</div>
</DocumentFragment>
`;
+1
View File
@@ -274,6 +274,7 @@ export function createTestClient(): MatrixClient {
matrixRTC: createStubMatrixRTC(), matrixRTC: createStubMatrixRTC(),
isFallbackICEServerAllowed: jest.fn().mockReturnValue(false), isFallbackICEServerAllowed: jest.fn().mockReturnValue(false),
getAuthIssuer: jest.fn(), getAuthIssuer: jest.fn(),
getOrCreateFilter: jest.fn(),
} as unknown as MatrixClient; } as unknown as MatrixClient;
client.reEmitter = new ReEmitter(client); client.reEmitter = new ReEmitter(client);