Refactor RoomStatusBar into MVVM (#31523)
* Refactor RoomStatusBar into MVVM * cleanup * updated snaps * More cleanup * fix loop * fixup * drop comment * lint * cleanup console statements * Starting to move to a MVVM v2 component. * extra * Refactor as a shared-componend / MVVM v2 * some cleanup * i18n for banner * remove removed css * Update playwright tests to have a two stage on the consent bar. * Update snaps * Update snapshots * cleanup * update snaps * refactor to use enum * fix slight differences in pw snaps * Add unit tests * fix snaps * snaps updated * more test cleanups * fix snaps * fixed now? * Disable animationsq * lint lint lint * remove console * lint * fix snap * Refactor based on review comments. * update view model test * oops! * fix snap * Update snaps * snap snap snap * switch to a const map of strings * Use this.disposables * Update translations to be inside shared-components * fix the tac * Also retry * Cleanup * update snaps * update other snaps * snap updates
This commit is contained in:
@@ -20,7 +20,7 @@ const config: TestRunnerConfig = {
|
||||
|
||||
// If you want to take screenshot of multiple browsers, use
|
||||
// page.context().browser().browserType().name() to get the browser name to prefix the file name
|
||||
const image = await page.screenshot();
|
||||
const image = await page.screenshot({ animations: "disabled" });
|
||||
expect(image).toMatchImageSnapshot({
|
||||
customSnapshotsDir,
|
||||
customSnapshotIdentifier: `${context.id}-${process.platform}`,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -12,6 +12,7 @@ import React, {
|
||||
type ReactNode,
|
||||
type PropsWithChildren,
|
||||
useMemo,
|
||||
type HTMLAttributes,
|
||||
} from "react";
|
||||
import { Button } from "@vector-im/compound-web";
|
||||
import CheckCircleIcon from "@vector-im/compound-design-tokens/assets/web/icons/check-circle";
|
||||
@@ -32,8 +33,6 @@ interface BannerProps {
|
||||
*/
|
||||
avatar?: React.ReactNode;
|
||||
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Actions presented to the user in the right-hand side of the banner alongside the dismiss button.
|
||||
*/
|
||||
@@ -60,21 +59,21 @@ export function Banner({
|
||||
actions,
|
||||
onClose,
|
||||
...props
|
||||
}: PropsWithChildren<BannerProps>): ReactElement {
|
||||
}: PropsWithChildren<BannerProps & HTMLAttributes<HTMLDivElement>>): ReactElement {
|
||||
const classes = classNames(styles.banner, className);
|
||||
|
||||
const icon = useMemo(() => {
|
||||
const icon = useMemo((): ReactElement => {
|
||||
switch (type) {
|
||||
case "critical":
|
||||
return <ErrorIcon fontSize={24} {...props} />;
|
||||
return <ErrorIcon fontSize={24} />;
|
||||
case "info":
|
||||
return <InfoIcon fontSize={24} {...props} />;
|
||||
return <InfoIcon fontSize={24} />;
|
||||
case "success":
|
||||
return <CheckCircleIcon fontSize={24} {...props} />;
|
||||
return <CheckCircleIcon fontSize={24} />;
|
||||
default:
|
||||
return <InfoIcon fontSize={24} {...props} />;
|
||||
return <InfoIcon fontSize={24} />;
|
||||
}
|
||||
}, [type, props]);
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
<div {...props} className={classes} data-type={type}>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"explore_rooms": "Explore rooms",
|
||||
"pause": "Pause",
|
||||
"play": "Play",
|
||||
"retry": "Retry",
|
||||
"search": "Search"
|
||||
},
|
||||
"left_panel": {
|
||||
@@ -15,9 +16,24 @@
|
||||
},
|
||||
"room": {
|
||||
"status_bar": {
|
||||
"history_visible": "This room has been configured so that new members can read history. <a>Learn More</a>"
|
||||
"delete_all": "Delete all",
|
||||
"exceeded_resource_limit_description": "Please contact your service administrator to continue using the service.",
|
||||
"exceeded_resource_limit_title": "Your message wasn't sent because this homeserver has exceeded a resource limit.",
|
||||
"failed_to_create_room_title": "Could not start a chat with this user",
|
||||
"history_visible": "This room has been configured so that new members can read history. <a>Learn More</a>",
|
||||
"homeserver_blocked_title": "Your message wasn't sent because this homeserver has been blocked by its administrator.",
|
||||
"monthly_user_limit_reached_title": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit.",
|
||||
"requires_consent_agreement_title": "You can't send any messages until you review and agree to our terms and conditions.",
|
||||
"retry_all": "Retry all",
|
||||
"select_messages_to_retry": "You can select all or individual messages to retry or delete",
|
||||
"server_connectivity_lost_description": "Sent messages will be stored until your connection has returned.",
|
||||
"server_connectivity_lost_title": "Connectivity to the server has been lost.",
|
||||
"some_messages_not_sent": "Some of your messages have not been sent"
|
||||
}
|
||||
},
|
||||
"terms": {
|
||||
"tac_button": "Review terms and conditions"
|
||||
},
|
||||
"time": {
|
||||
"about_day_ago": "about a day ago",
|
||||
"about_hour_ago": "about an hour ago",
|
||||
|
||||
@@ -17,6 +17,7 @@ export * from "./event-tiles/TextualEventView";
|
||||
export * from "./message-body/MediaBody";
|
||||
export * from "./pill-input/Pill";
|
||||
export * from "./pill-input/PillInput";
|
||||
export * from "./room/RoomStatusBar";
|
||||
export * from "./rich-list/RichItem";
|
||||
export * from "./rich-list/RichList";
|
||||
export * from "./room-list/RoomListSearchView";
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.container {
|
||||
color: var(--cpd-color-text-primary);
|
||||
svg {
|
||||
/* Ensure button icons are primary too */
|
||||
color: var(--cpd-color-text-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
import { type Meta, type StoryFn } from "@storybook/react-vite";
|
||||
import React, { type JSX } from "react";
|
||||
import { fn } from "storybook/test";
|
||||
|
||||
import { useMockedViewModel } from "../../useMockedViewModel";
|
||||
import {
|
||||
RoomStatusBarState,
|
||||
RoomStatusBarView,
|
||||
type RoomStatusBarViewActions,
|
||||
type RoomStatusBarViewSnapshot,
|
||||
} from "./RoomStatusBarView";
|
||||
|
||||
type RoomStatusBarProps = RoomStatusBarViewSnapshot & RoomStatusBarViewActions;
|
||||
|
||||
const RoomStatusBarViewWrapper = ({
|
||||
onResendAllClick,
|
||||
onDeleteAllClick,
|
||||
onRetryRoomCreationClick,
|
||||
onTermsAndConditionsClicked,
|
||||
...rest
|
||||
}: RoomStatusBarProps): JSX.Element => {
|
||||
const vm = useMockedViewModel(rest, {
|
||||
onResendAllClick,
|
||||
onDeleteAllClick,
|
||||
onRetryRoomCreationClick,
|
||||
onTermsAndConditionsClicked,
|
||||
});
|
||||
return <RoomStatusBarView vm={vm} />;
|
||||
};
|
||||
|
||||
export default {
|
||||
title: "room/RoomStatusBarView",
|
||||
component: RoomStatusBarViewWrapper,
|
||||
tags: ["autodocs"],
|
||||
argTypes: {},
|
||||
args: {
|
||||
onResendAllClick: fn(),
|
||||
onDeleteAllClick: fn(),
|
||||
onRetryRoomCreationClick: fn(),
|
||||
onTermsAndConditionsClicked: fn(),
|
||||
},
|
||||
} as Meta<typeof RoomStatusBarViewWrapper>;
|
||||
|
||||
const Template: StoryFn<typeof RoomStatusBarViewWrapper> = (args) => <RoomStatusBarViewWrapper {...args} />;
|
||||
|
||||
/**
|
||||
* Rendered when the client has lost connection with the server.
|
||||
*/
|
||||
export const WithConnectionLost = Template.bind({});
|
||||
WithConnectionLost.args = {
|
||||
state: RoomStatusBarState.ConnectionLost,
|
||||
};
|
||||
|
||||
/**
|
||||
* Rendered when the client needs the user to consent to some terms and conditions before
|
||||
* they can perform any room actions.
|
||||
*/
|
||||
export const WithConsentLink = Template.bind({});
|
||||
WithConsentLink.args = {
|
||||
state: RoomStatusBarState.NeedsConsent,
|
||||
consentUri: "#example",
|
||||
};
|
||||
|
||||
/**
|
||||
* Rendered when the server has hit a usage limit and is forbidding the user from performing
|
||||
* any actions in the room. There is an optional parameter to link to an admin to contact.
|
||||
*/
|
||||
export const WithResourceLimit = Template.bind({});
|
||||
WithResourceLimit.args = {
|
||||
state: RoomStatusBarState.ResourceLimited,
|
||||
resourceLimit: "hs_disabled",
|
||||
adminContactHref: "#example",
|
||||
};
|
||||
|
||||
/**
|
||||
* Rendered when the client has some unsent messages in the room, stored locally.
|
||||
*/
|
||||
export const WithUnsentMessages = Template.bind({});
|
||||
WithUnsentMessages.args = {
|
||||
state: RoomStatusBarState.UnsentMessages,
|
||||
isResending: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Rendered when the client has some unsent messages in the room, stored locally and is
|
||||
* trying to send them.
|
||||
*/
|
||||
export const WithUnsentMessagesSending = Template.bind({});
|
||||
WithUnsentMessagesSending.args = {
|
||||
state: RoomStatusBarState.UnsentMessages,
|
||||
isResending: true,
|
||||
};
|
||||
/**
|
||||
* Rendered when a local room has failed to be created.
|
||||
*/
|
||||
export const WithLocalRoomRetry = Template.bind({});
|
||||
WithLocalRoomRetry.args = {
|
||||
state: RoomStatusBarState.LocalRoomFailed,
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
import { composeStories } from "@storybook/react-vite";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import * as stories from "./RoomStatusBarView.stories.tsx";
|
||||
|
||||
const { WithConnectionLost, WithConsentLink, WithResourceLimit, WithUnsentMessages, WithLocalRoomRetry } =
|
||||
composeStories(stories);
|
||||
|
||||
describe("RoomStatusBarView", () => {
|
||||
it("renders connection lost", () => {
|
||||
const { container } = render(<WithConnectionLost />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders resource limit error", () => {
|
||||
const { container } = render(<WithResourceLimit />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders consent link", () => {
|
||||
const { container, getByRole } = render(<WithConsentLink />);
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
const button = getByRole("link");
|
||||
expect(button.getAttribute("href")).toEqual("#example");
|
||||
});
|
||||
it("renders unsent messages", async () => {
|
||||
const { container } = render(
|
||||
<WithUnsentMessages onDeleteAllClick={jest.fn()} onRetryRoomCreationClick={jest.fn()} />,
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders unsent messages and deletes all", async () => {
|
||||
const onDeleteAllClick = jest.fn();
|
||||
const { container, getByRole } = render(<WithUnsentMessages onDeleteAllClick={onDeleteAllClick} />);
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
const button = getByRole("button", { name: "Delete all" });
|
||||
await userEvent.click(button);
|
||||
expect(onDeleteAllClick).toHaveBeenCalled();
|
||||
});
|
||||
it("renders unsent messages and resends all", async () => {
|
||||
const onResendAllClick = jest.fn();
|
||||
const { container, getByRole } = render(<WithUnsentMessages onResendAllClick={onResendAllClick} />);
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
const button = getByRole("button", { name: "Retry all" });
|
||||
await userEvent.click(button);
|
||||
expect(onResendAllClick).toHaveBeenCalled();
|
||||
});
|
||||
it("renders local room error", async () => {
|
||||
const onRetryRoomCreationClick = jest.fn();
|
||||
const { container, getByRole } = render(
|
||||
<WithLocalRoomRetry onRetryRoomCreationClick={onRetryRoomCreationClick} />,
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
const button = getByRole("button", { name: "Retry" });
|
||||
await userEvent.click(button);
|
||||
expect(onRetryRoomCreationClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useId, type JSX } from "react";
|
||||
import { RestartIcon, DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { Button, InlineSpinner, Text } from "@vector-im/compound-web";
|
||||
|
||||
import styles from "./RoomStatusBarView.module.css";
|
||||
import { useViewModel } from "../../useViewModel";
|
||||
import { type ViewModel } from "../../viewmodel";
|
||||
import { useI18n } from "../../utils/i18nContext";
|
||||
import { Banner } from "../../composer/Banner";
|
||||
export interface RoomStatusBarViewActions {
|
||||
/**
|
||||
* Called when the user clicks on the 'resend all' button in the 'unsent messages' bar.
|
||||
*/
|
||||
onResendAllClick?: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Called when the user clicks on the 'cancel all' button in the 'unsent messages' bar.
|
||||
*/
|
||||
onDeleteAllClick?: () => void;
|
||||
|
||||
/**
|
||||
* Called when the user clicks on the 'Retry' button in the 'failed to start chat' bar.
|
||||
*/
|
||||
onRetryRoomCreationClick?: () => void;
|
||||
|
||||
/**
|
||||
* Called when the user clicks on the 'Review Terms and Conditions' button.
|
||||
*/
|
||||
onTermsAndConditionsClicked?: () => void;
|
||||
}
|
||||
|
||||
export const RoomStatusBarState = {
|
||||
/**
|
||||
* Connectivity to the homeserver has been lost. The user can not take any actions
|
||||
* until the connection is restored.
|
||||
*/
|
||||
ConnectionLost: "ConnectionLost",
|
||||
/**
|
||||
* The homeserver has indiciated the user needs to consent to the Terms and Conditions
|
||||
* before they can send a message.
|
||||
*/
|
||||
NeedsConsent: "NeedsConsent",
|
||||
/**
|
||||
* The homeserver has indiciated that messages can not be sent due to a resource limit
|
||||
* being reached. The user may use the given admin contact details.
|
||||
*/
|
||||
ResourceLimited: "ResourceLimited",
|
||||
/**
|
||||
* There are messages stored locally that previously failed to send that the user
|
||||
* may now retry or delete.
|
||||
*/
|
||||
UnsentMessages: "UnsentMessages",
|
||||
/**
|
||||
* There was an error creating a room. The user may retry creation.
|
||||
*/
|
||||
LocalRoomFailed: "LocalRoomFailed",
|
||||
} as const;
|
||||
|
||||
export interface RoomStatusBarNotVisible {
|
||||
state: null;
|
||||
}
|
||||
|
||||
export interface RoomStatusBarNoConnection {
|
||||
state: "ConnectionLost";
|
||||
}
|
||||
|
||||
export interface RoomStatusBarConsentState {
|
||||
state: "NeedsConsent";
|
||||
consentUri: string;
|
||||
}
|
||||
|
||||
export interface RoomStatusBarResourceLimitedState {
|
||||
state: "ResourceLimited";
|
||||
resourceLimit: "monthly_active_user" | "hs_disabled" | string;
|
||||
adminContactHref?: string;
|
||||
}
|
||||
|
||||
export interface RoomStatusBarUnsentMessagesState {
|
||||
state: "UnsentMessages";
|
||||
isResending: boolean;
|
||||
}
|
||||
export interface RoomStatusBarLocalRoomError {
|
||||
state: "LocalRoomFailed";
|
||||
}
|
||||
|
||||
export type RoomStatusBarViewSnapshot =
|
||||
| RoomStatusBarNoConnection
|
||||
| RoomStatusBarConsentState
|
||||
| RoomStatusBarResourceLimitedState
|
||||
| RoomStatusBarUnsentMessagesState
|
||||
| RoomStatusBarLocalRoomError
|
||||
| RoomStatusBarNotVisible;
|
||||
|
||||
/**
|
||||
* The view model for RoomStatusBarView.
|
||||
*/
|
||||
export type RoomStatusBarViewModel = ViewModel<RoomStatusBarViewSnapshot> & RoomStatusBarViewActions;
|
||||
|
||||
interface RoomStatusBarViewProps {
|
||||
/**
|
||||
* The view model for the banner.
|
||||
*/
|
||||
vm: RoomStatusBarViewModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* A component to alert to a failure in the context of a room.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <RoomStatusBarView vm={RoomStatusBarViewModel} />
|
||||
* ```
|
||||
*/
|
||||
export function RoomStatusBarView({ vm }: Readonly<RoomStatusBarViewProps>): JSX.Element | null {
|
||||
const { translate: _t } = useI18n();
|
||||
const snapshot = useViewModel(vm);
|
||||
const bannerTitleId = useId();
|
||||
|
||||
const deleteAllClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
vm.onDeleteAllClick?.();
|
||||
},
|
||||
[vm],
|
||||
);
|
||||
|
||||
const resendClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
void vm.onResendAllClick?.();
|
||||
},
|
||||
[vm],
|
||||
);
|
||||
|
||||
const retryRoomCreationClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
vm.onRetryRoomCreationClick?.();
|
||||
},
|
||||
[vm],
|
||||
);
|
||||
|
||||
const termsAndConditionsClicked = useCallback<React.MouseEventHandler<HTMLAnchorElement>>(() => {
|
||||
// Allow the link to go through.
|
||||
vm.onTermsAndConditionsClicked?.();
|
||||
}, [vm]);
|
||||
|
||||
if (snapshot.state === null) {
|
||||
// Nothing to show!
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (snapshot.state) {
|
||||
case RoomStatusBarState.ConnectionLost:
|
||||
return (
|
||||
<Banner type="critical" role="status" aria-labelledby={bannerTitleId}>
|
||||
<div className={styles.container}>
|
||||
<Text id={bannerTitleId} weight="semibold">
|
||||
{_t("room|status_bar|server_connectivity_lost_title")}
|
||||
</Text>
|
||||
<Text className={styles.description} size="sm">
|
||||
{_t("room|status_bar|server_connectivity_lost_description")}
|
||||
</Text>
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
case RoomStatusBarState.NeedsConsent:
|
||||
return (
|
||||
<Banner
|
||||
type="critical"
|
||||
role="status"
|
||||
aria-labelledby={bannerTitleId}
|
||||
actions={
|
||||
<Button
|
||||
onClick={termsAndConditionsClicked}
|
||||
kind="secondary"
|
||||
size="sm"
|
||||
as="a"
|
||||
href={snapshot.consentUri}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
{_t("terms|tac_button")}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<Text id={bannerTitleId} weight="semibold">
|
||||
{_t("room|status_bar|requires_consent_agreement_title")}
|
||||
</Text>
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
case RoomStatusBarState.ResourceLimited:
|
||||
return (
|
||||
<Banner
|
||||
type="critical"
|
||||
role="status"
|
||||
aria-labelledby={bannerTitleId}
|
||||
actions={
|
||||
snapshot.adminContactHref && (
|
||||
<Button
|
||||
kind="secondary"
|
||||
size="sm"
|
||||
as="a"
|
||||
href={snapshot.adminContactHref}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Contact admin
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<Text id={bannerTitleId} weight="semibold">
|
||||
{{
|
||||
monthly_active_user: _t("room|status_bar|monthly_user_limit_reached_title"),
|
||||
hs_disabled: _t("room|status_bar|homeserver_blocked_title"),
|
||||
}[snapshot.resourceLimit] || _t("room|status_bar|exceeded_resource_limit_title")}
|
||||
</Text>
|
||||
<Text className={styles.description} size="sm">
|
||||
{_t("room|status_bar|exceeded_resource_limit_description")}
|
||||
</Text>
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
case RoomStatusBarState.LocalRoomFailed:
|
||||
return (
|
||||
<Banner
|
||||
role="status"
|
||||
type="critical"
|
||||
aria-labelledby={bannerTitleId}
|
||||
actions={
|
||||
<Button
|
||||
size="sm"
|
||||
kind="secondary"
|
||||
className={styles.container}
|
||||
Icon={RestartIcon}
|
||||
onClick={retryRoomCreationClick}
|
||||
>
|
||||
{_t("action|retry")}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Text id={bannerTitleId} weight="semibold" className={styles.container}>
|
||||
{_t("room|status_bar|failed_to_create_room_title")}
|
||||
</Text>
|
||||
</Banner>
|
||||
);
|
||||
case RoomStatusBarState.UnsentMessages:
|
||||
return (
|
||||
<Banner
|
||||
role="status"
|
||||
type="critical"
|
||||
actions={
|
||||
snapshot.isResending ? (
|
||||
<InlineSpinner />
|
||||
) : (
|
||||
<>
|
||||
{vm.onDeleteAllClick && (
|
||||
<Button
|
||||
size="sm"
|
||||
kind="destructive"
|
||||
Icon={DeleteIcon}
|
||||
disabled={snapshot.isResending}
|
||||
onClick={deleteAllClick}
|
||||
>
|
||||
{_t("room|status_bar|delete_all")}
|
||||
</Button>
|
||||
)}
|
||||
{vm.onResendAllClick && (
|
||||
<Button
|
||||
size="sm"
|
||||
kind="secondary"
|
||||
Icon={RestartIcon}
|
||||
disabled={snapshot.isResending}
|
||||
onClick={resendClick}
|
||||
className={styles.container}
|
||||
>
|
||||
{_t("room|status_bar|retry_all")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
aria-labelledby={bannerTitleId}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<Text id={bannerTitleId} weight="semibold">
|
||||
{_t("room|status_bar|some_messages_not_sent")}
|
||||
</Text>
|
||||
<Text className={styles.description} size="sm">
|
||||
{_t("room|status_bar|select_messages_to_retry")}
|
||||
</Text>
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
default:
|
||||
// We should never get into this state.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`RoomStatusBarView renders connection lost 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_0_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_0_"
|
||||
>
|
||||
Connectivity to the server has been lost.
|
||||
</p>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 description"
|
||||
>
|
||||
Sent messages will be stored until your connection has returned.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders consent link 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_2_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_2_"
|
||||
>
|
||||
You can't send any messages until you review and agree to our terms and conditions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<a
|
||||
class="_button_13vu4_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
href="#example"
|
||||
rel="noreferrer noopener"
|
||||
role="link"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
Review terms and conditions
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders local room error 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_6_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55 container"
|
||||
id="_r_6_"
|
||||
>
|
||||
Could not start a chat with this user
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_13vu4_8 container _has-icon_13vu4_60"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
|
||||
/>
|
||||
</svg>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders resource limit error 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_1_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_1_"
|
||||
>
|
||||
Your message wasn't sent because this homeserver has been blocked by its administrator.
|
||||
</p>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 description"
|
||||
>
|
||||
Please contact your service administrator to continue using the service.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<a
|
||||
class="_button_13vu4_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
href="#example"
|
||||
rel="noreferrer noopener"
|
||||
role="link"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
Contact admin
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders unsent messages 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_3_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_3_"
|
||||
>
|
||||
Some of your messages have not been sent
|
||||
</p>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 description"
|
||||
>
|
||||
You can select all or individual messages to retry or delete
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 _has-icon_13vu4_60 _destructive_13vu4_110"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 21q-.824 0-1.412-.587A1.93 1.93 0 0 1 5 19V6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 4 5q0-.424.287-.713A.97.97 0 0 1 5 4h4q0-.424.287-.712A.97.97 0 0 1 10 3h4q.424 0 .713.288Q15 3.575 15 4h4q.424 0 .712.287Q20 4.576 20 5t-.288.713A.97.97 0 0 1 19 6v13q0 .824-.587 1.413A1.93 1.93 0 0 1 17 21zM7 6v13h10V6zm2 10q0 .424.287.712Q9.576 17 10 17t.713-.288A.97.97 0 0 0 11 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 10 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 9 9zm4 0q0 .424.287.712.288.288.713.288.424 0 .713-.288A.97.97 0 0 0 15 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 14 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 13 9z"
|
||||
/>
|
||||
</svg>
|
||||
Delete all
|
||||
</button>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 container _has-icon_13vu4_60"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
|
||||
/>
|
||||
</svg>
|
||||
Retry all
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders unsent messages and deletes all 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_4_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_4_"
|
||||
>
|
||||
Some of your messages have not been sent
|
||||
</p>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 description"
|
||||
>
|
||||
You can select all or individual messages to retry or delete
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 _has-icon_13vu4_60 _destructive_13vu4_110"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 21q-.824 0-1.412-.587A1.93 1.93 0 0 1 5 19V6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 4 5q0-.424.287-.713A.97.97 0 0 1 5 4h4q0-.424.287-.712A.97.97 0 0 1 10 3h4q.424 0 .713.288Q15 3.575 15 4h4q.424 0 .712.287Q20 4.576 20 5t-.288.713A.97.97 0 0 1 19 6v13q0 .824-.587 1.413A1.93 1.93 0 0 1 17 21zM7 6v13h10V6zm2 10q0 .424.287.712Q9.576 17 10 17t.713-.288A.97.97 0 0 0 11 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 10 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 9 9zm4 0q0 .424.287.712.288.288.713.288.424 0 .713-.288A.97.97 0 0 0 15 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 14 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 13 9z"
|
||||
/>
|
||||
</svg>
|
||||
Delete all
|
||||
</button>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 container _has-icon_13vu4_60"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
|
||||
/>
|
||||
</svg>
|
||||
Retry all
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`RoomStatusBarView renders unsent messages and resends all 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-labelledby="_r_5_"
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-md-semibold_6v6n8_55"
|
||||
id="_r_5_"
|
||||
>
|
||||
Some of your messages have not been sent
|
||||
</p>
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 description"
|
||||
>
|
||||
You can select all or individual messages to retry or delete
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 _has-icon_13vu4_60 _destructive_13vu4_110"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 21q-.824 0-1.412-.587A1.93 1.93 0 0 1 5 19V6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 4 5q0-.424.287-.713A.97.97 0 0 1 5 4h4q0-.424.287-.712A.97.97 0 0 1 10 3h4q.424 0 .713.288Q15 3.575 15 4h4q.424 0 .712.287Q20 4.576 20 5t-.288.713A.97.97 0 0 1 19 6v13q0 .824-.587 1.413A1.93 1.93 0 0 1 17 21zM7 6v13h10V6zm2 10q0 .424.287.712Q9.576 17 10 17t.713-.288A.97.97 0 0 0 11 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 10 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 9 9zm4 0q0 .424.287.712.288.288.713.288.424 0 .713-.288A.97.97 0 0 0 15 16V9a.97.97 0 0 0-.287-.713A.97.97 0 0 0 14 8a.97.97 0 0 0-.713.287A.97.97 0 0 0 13 9z"
|
||||
/>
|
||||
</svg>
|
||||
Delete all
|
||||
</button>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
class="_button_13vu4_8 container _has-icon_13vu4_60"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
|
||||
/>
|
||||
</svg>
|
||||
Retry all
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
export * from "./RoomStatusBarView";
|
||||
Reference in New Issue
Block a user