Apply prettier formatting
This commit is contained in:
parent
1cac306093
commit
526645c791
1576 changed files with 65385 additions and 62478 deletions
|
@ -14,32 +14,32 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { EventTimelineSet } from 'matrix-js-sdk/src/models/event-timeline-set';
|
||||
import { Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set";
|
||||
import { Thread } from "matrix-js-sdk/src/models/thread";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import BaseCard from "../views/right_panel/BaseCard";
|
||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||
import MatrixClientContext from '../../contexts/MatrixClientContext';
|
||||
import { _t } from '../../languageHandler';
|
||||
import { ContextMenuButton } from '../../accessibility/context_menu/ContextMenuButton';
|
||||
import ContextMenu, { ChevronFace, MenuItemRadio, useContextMenu } from './ContextMenu';
|
||||
import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
|
||||
import TimelinePanel from './TimelinePanel';
|
||||
import { Layout } from '../../settings/enums/Layout';
|
||||
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||
import Measured from '../views/elements/Measured';
|
||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { ContextMenuButton } from "../../accessibility/context_menu/ContextMenuButton";
|
||||
import ContextMenu, { ChevronFace, MenuItemRadio, useContextMenu } from "./ContextMenu";
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import TimelinePanel from "./TimelinePanel";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
||||
import Measured from "../views/elements/Measured";
|
||||
import PosthogTrackers from "../../PosthogTrackers";
|
||||
import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
|
||||
import { BetaPill } from '../views/beta/BetaCard';
|
||||
import Modal from '../../Modal';
|
||||
import BetaFeedbackDialog from '../views/dialogs/BetaFeedbackDialog';
|
||||
import { Action } from '../../dispatcher/actions';
|
||||
import { UserTab } from '../views/dialogs/UserTab';
|
||||
import dis from '../../dispatcher/dispatcher';
|
||||
import { BetaPill } from "../views/beta/BetaCard";
|
||||
import Modal from "../../Modal";
|
||||
import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog";
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import { UserTab } from "../views/dialogs/UserTab";
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
import Heading from '../views/typography/Heading';
|
||||
import Heading from "../views/typography/Heading";
|
||||
import { shouldShowFeedback } from "../../utils/Feedback";
|
||||
|
||||
interface IProps {
|
||||
|
@ -51,7 +51,7 @@ interface IProps {
|
|||
|
||||
export enum ThreadFilterType {
|
||||
"My",
|
||||
"All"
|
||||
"All",
|
||||
}
|
||||
|
||||
type ThreadPanelHeaderOption = {
|
||||
|
@ -69,17 +69,19 @@ export const ThreadPanelHeaderFilterOptionItem = ({
|
|||
onClick: () => void;
|
||||
isSelected: boolean;
|
||||
}) => {
|
||||
return <MenuItemRadio
|
||||
active={isSelected}
|
||||
className="mx_ThreadPanel_Header_FilterOptionItem"
|
||||
onClick={onClick}
|
||||
>
|
||||
<span>{ label }</span>
|
||||
<span>{ description }</span>
|
||||
</MenuItemRadio>;
|
||||
return (
|
||||
<MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}>
|
||||
<span>{label}</span>
|
||||
<span>{description}</span>
|
||||
</MenuItemRadio>
|
||||
);
|
||||
};
|
||||
|
||||
export const ThreadPanelHeader = ({ filterOption, setFilterOption, empty }: {
|
||||
export const ThreadPanelHeader = ({
|
||||
filterOption,
|
||||
setFilterOption,
|
||||
empty,
|
||||
}: {
|
||||
filterOption: ThreadFilterType;
|
||||
setFilterOption: (filterOption: ThreadFilterType) => void;
|
||||
empty: boolean;
|
||||
|
@ -88,7 +90,7 @@ export const ThreadPanelHeader = ({ filterOption, setFilterOption, empty }: {
|
|||
const options: readonly ThreadPanelHeaderOption[] = [
|
||||
{
|
||||
label: _t("All threads"),
|
||||
description: _t('Shows all threads from current room'),
|
||||
description: _t("Shows all threads from current room"),
|
||||
key: ThreadFilterType.All,
|
||||
},
|
||||
{
|
||||
|
@ -98,43 +100,53 @@ export const ThreadPanelHeader = ({ filterOption, setFilterOption, empty }: {
|
|||
},
|
||||
];
|
||||
|
||||
const value = options.find(option => option.key === filterOption);
|
||||
const contextMenuOptions = options.map(opt => <ThreadPanelHeaderFilterOptionItem
|
||||
key={opt.key}
|
||||
label={opt.label}
|
||||
description={opt.description}
|
||||
onClick={() => {
|
||||
setFilterOption(opt.key);
|
||||
closeMenu();
|
||||
}}
|
||||
isSelected={opt === value}
|
||||
/>);
|
||||
const contextMenu = menuDisplayed ? <ContextMenu
|
||||
top={108}
|
||||
right={33}
|
||||
onFinished={closeMenu}
|
||||
chevronFace={ChevronFace.Top}
|
||||
wrapperClassName="mx_BaseCard_header_title"
|
||||
>
|
||||
{ contextMenuOptions }
|
||||
</ContextMenu> : null;
|
||||
return <div className="mx_BaseCard_header_title">
|
||||
<Heading size="h4" className="mx_BaseCard_header_title_heading">{ _t("Threads") }</Heading>
|
||||
{ !empty && <>
|
||||
<ContextMenuButton
|
||||
className="mx_ThreadPanel_dropdown"
|
||||
inputRef={button}
|
||||
isExpanded={menuDisplayed}
|
||||
onClick={(ev: ButtonEvent) => {
|
||||
openMenu();
|
||||
PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev);
|
||||
}}
|
||||
>
|
||||
{ `${_t('Show:')} ${value.label}` }
|
||||
</ContextMenuButton>
|
||||
{ contextMenu }
|
||||
</> }
|
||||
</div>;
|
||||
const value = options.find((option) => option.key === filterOption);
|
||||
const contextMenuOptions = options.map((opt) => (
|
||||
<ThreadPanelHeaderFilterOptionItem
|
||||
key={opt.key}
|
||||
label={opt.label}
|
||||
description={opt.description}
|
||||
onClick={() => {
|
||||
setFilterOption(opt.key);
|
||||
closeMenu();
|
||||
}}
|
||||
isSelected={opt === value}
|
||||
/>
|
||||
));
|
||||
const contextMenu = menuDisplayed ? (
|
||||
<ContextMenu
|
||||
top={108}
|
||||
right={33}
|
||||
onFinished={closeMenu}
|
||||
chevronFace={ChevronFace.Top}
|
||||
wrapperClassName="mx_BaseCard_header_title"
|
||||
>
|
||||
{contextMenuOptions}
|
||||
</ContextMenu>
|
||||
) : null;
|
||||
return (
|
||||
<div className="mx_BaseCard_header_title">
|
||||
<Heading size="h4" className="mx_BaseCard_header_title_heading">
|
||||
{_t("Threads")}
|
||||
</Heading>
|
||||
{!empty && (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="mx_ThreadPanel_dropdown"
|
||||
inputRef={button}
|
||||
isExpanded={menuDisplayed}
|
||||
onClick={(ev: ButtonEvent) => {
|
||||
openMenu();
|
||||
PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev);
|
||||
}}
|
||||
>
|
||||
{`${_t("Show:")} ${value.label}`}
|
||||
</ContextMenuButton>
|
||||
{contextMenu}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface EmptyThreadIProps {
|
||||
|
@ -146,46 +158,56 @@ interface EmptyThreadIProps {
|
|||
const EmptyThread: React.FC<EmptyThreadIProps> = ({ hasThreads, filterOption, showAllThreadsCallback }) => {
|
||||
let body: JSX.Element;
|
||||
if (hasThreads) {
|
||||
body = <>
|
||||
<p>
|
||||
{ _t("Reply to an ongoing thread or use “%(replyInThread)s” "
|
||||
+ "when hovering over a message to start a new one.", {
|
||||
replyInThread: _t("Reply in thread"),
|
||||
}) }
|
||||
</p>
|
||||
<p>
|
||||
{ /* Always display that paragraph to prevent layout shift when hiding the button */ }
|
||||
{ (filterOption === ThreadFilterType.My)
|
||||
? <button onClick={showAllThreadsCallback}>{ _t("Show all threads") }</button>
|
||||
: <> </>
|
||||
}
|
||||
</p>
|
||||
</>;
|
||||
body = (
|
||||
<>
|
||||
<p>
|
||||
{_t(
|
||||
"Reply to an ongoing thread or use “%(replyInThread)s” " +
|
||||
"when hovering over a message to start a new one.",
|
||||
{
|
||||
replyInThread: _t("Reply in thread"),
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{/* Always display that paragraph to prevent layout shift when hiding the button */}
|
||||
{filterOption === ThreadFilterType.My ? (
|
||||
<button onClick={showAllThreadsCallback}>{_t("Show all threads")}</button>
|
||||
) : (
|
||||
<> </>
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
body = <>
|
||||
<p>{ _t("Threads help keep your conversations on-topic and easy to track.") }</p>
|
||||
<p className="mx_ThreadPanel_empty_tip">
|
||||
{ _t('<b>Tip:</b> Use “%(replyInThread)s” when hovering over a message.', {
|
||||
replyInThread: _t("Reply in thread"),
|
||||
}, {
|
||||
b: sub => <b>{ sub }</b>,
|
||||
}) }
|
||||
</p>
|
||||
</>;
|
||||
body = (
|
||||
<>
|
||||
<p>{_t("Threads help keep your conversations on-topic and easy to track.")}</p>
|
||||
<p className="mx_ThreadPanel_empty_tip">
|
||||
{_t(
|
||||
"<b>Tip:</b> Use “%(replyInThread)s” when hovering over a message.",
|
||||
{
|
||||
replyInThread: _t("Reply in thread"),
|
||||
},
|
||||
{
|
||||
b: (sub) => <b>{sub}</b>,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <aside className="mx_ThreadPanel_empty">
|
||||
<div className="mx_ThreadPanel_largeIcon" />
|
||||
<h2>{ _t("Keep discussions organised with threads") }</h2>
|
||||
{ body }
|
||||
</aside>;
|
||||
return (
|
||||
<aside className="mx_ThreadPanel_empty">
|
||||
<div className="mx_ThreadPanel_largeIcon" />
|
||||
<h2>{_t("Keep discussions organised with threads")}</h2>
|
||||
{body}
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
const ThreadPanel: React.FC<IProps> = ({
|
||||
roomId,
|
||||
onClose,
|
||||
permalinkCreator,
|
||||
}) => {
|
||||
const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) => {
|
||||
const mxClient = useContext(MatrixClientContext);
|
||||
const roomContext = useContext(RoomContext);
|
||||
const timelinePanel = useRef<TimelinePanel>();
|
||||
|
@ -198,12 +220,14 @@ const ThreadPanel: React.FC<IProps> = ({
|
|||
|
||||
useEffect(() => {
|
||||
const room = mxClient.getRoom(roomId);
|
||||
room.createThreadsTimelineSets().then(() => {
|
||||
return room.fetchRoomThreads();
|
||||
}).then(() => {
|
||||
setFilterOption(ThreadFilterType.All);
|
||||
setRoom(room);
|
||||
});
|
||||
room.createThreadsTimelineSets()
|
||||
.then(() => {
|
||||
return room.fetchRoomThreads();
|
||||
})
|
||||
.then(() => {
|
||||
setFilterOption(ThreadFilterType.All);
|
||||
setRoom(room);
|
||||
});
|
||||
}, [mxClient, roomId]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -222,53 +246,66 @@ const ThreadPanel: React.FC<IProps> = ({
|
|||
}
|
||||
}, [timelineSet, timelinePanel]);
|
||||
|
||||
const openFeedback = shouldShowFeedback() ? () => {
|
||||
Modal.createDialog(BetaFeedbackDialog, {
|
||||
featureId: "feature_thread",
|
||||
});
|
||||
} : null;
|
||||
const openFeedback = shouldShowFeedback()
|
||||
? () => {
|
||||
Modal.createDialog(BetaFeedbackDialog, {
|
||||
featureId: "feature_thread",
|
||||
});
|
||||
}
|
||||
: null;
|
||||
|
||||
return (
|
||||
<RoomContext.Provider value={{
|
||||
...roomContext,
|
||||
timelineRenderingType: TimelineRenderingType.ThreadsList,
|
||||
showHiddenEvents: true,
|
||||
narrow,
|
||||
}}>
|
||||
<RoomContext.Provider
|
||||
value={{
|
||||
...roomContext,
|
||||
timelineRenderingType: TimelineRenderingType.ThreadsList,
|
||||
showHiddenEvents: true,
|
||||
narrow,
|
||||
}}
|
||||
>
|
||||
<BaseCard
|
||||
header={<ThreadPanelHeader
|
||||
filterOption={filterOption}
|
||||
setFilterOption={setFilterOption}
|
||||
empty={!timelineSet?.getLiveTimeline()?.getEvents().length}
|
||||
/>}
|
||||
footer={<>
|
||||
<BetaPill
|
||||
tooltipTitle={_t("Threads are a beta feature")}
|
||||
tooltipCaption={_t("Click for more info")}
|
||||
onClick={() => {
|
||||
dis.dispatch({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Labs,
|
||||
});
|
||||
}}
|
||||
header={
|
||||
<ThreadPanelHeader
|
||||
filterOption={filterOption}
|
||||
setFilterOption={setFilterOption}
|
||||
empty={!timelineSet?.getLiveTimeline()?.getEvents().length}
|
||||
/>
|
||||
{ openFeedback && _t("<a>Give feedback</a>", {}, {
|
||||
a: sub =>
|
||||
<AccessibleButton kind="link_inline" onClick={openFeedback}>{ sub }</AccessibleButton>,
|
||||
}) }
|
||||
</>}
|
||||
}
|
||||
footer={
|
||||
<>
|
||||
<BetaPill
|
||||
tooltipTitle={_t("Threads are a beta feature")}
|
||||
tooltipCaption={_t("Click for more info")}
|
||||
onClick={() => {
|
||||
dis.dispatch({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Labs,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{openFeedback &&
|
||||
_t(
|
||||
"<a>Give feedback</a>",
|
||||
{},
|
||||
{
|
||||
a: (sub) => (
|
||||
<AccessibleButton kind="link_inline" onClick={openFeedback}>
|
||||
{sub}
|
||||
</AccessibleButton>
|
||||
),
|
||||
},
|
||||
)}
|
||||
</>
|
||||
}
|
||||
className="mx_ThreadPanel"
|
||||
onClose={onClose}
|
||||
withoutScrollContainer={true}
|
||||
ref={card}
|
||||
>
|
||||
<Measured
|
||||
sensor={card.current}
|
||||
onMeasurement={setNarrow}
|
||||
/>
|
||||
{ timelineSet
|
||||
? <TimelinePanel
|
||||
key={timelineSet.getFilter()?.filterId ?? (roomId + ":" + filterOption)}
|
||||
<Measured sensor={card.current} onMeasurement={setNarrow} />
|
||||
{timelineSet ? (
|
||||
<TimelinePanel
|
||||
key={timelineSet.getFilter()?.filterId ?? roomId + ":" + filterOption}
|
||||
ref={timelinePanel}
|
||||
showReadReceipts={false} // No RR support in thread's list
|
||||
manageReadReceipts={false} // No RR support in thread's list
|
||||
|
@ -276,11 +313,13 @@ const ThreadPanel: React.FC<IProps> = ({
|
|||
sendReadReceiptOnLoad={false} // No RR support in thread's list
|
||||
timelineSet={timelineSet}
|
||||
showUrlPreview={false} // No URL previews at the threads list level
|
||||
empty={<EmptyThread
|
||||
hasThreads={room.threadsTimelineSets?.[0]?.getLiveTimeline().getEvents().length > 0}
|
||||
filterOption={filterOption}
|
||||
showAllThreadsCallback={() => setFilterOption(ThreadFilterType.All)}
|
||||
/>}
|
||||
empty={
|
||||
<EmptyThread
|
||||
hasThreads={room.threadsTimelineSets?.[0]?.getLiveTimeline().getEvents().length > 0}
|
||||
filterOption={filterOption}
|
||||
showAllThreadsCallback={() => setFilterOption(ThreadFilterType.All)}
|
||||
/>
|
||||
}
|
||||
alwaysShowTimestamps={true}
|
||||
layout={Layout.Group}
|
||||
hideThreadedMessages={false}
|
||||
|
@ -291,10 +330,11 @@ const ThreadPanel: React.FC<IProps> = ({
|
|||
permalinkCreator={permalinkCreator}
|
||||
disableGrouping={true}
|
||||
/>
|
||||
: <div className="mx_AutoHideScrollbar">
|
||||
) : (
|
||||
<div className="mx_AutoHideScrollbar">
|
||||
<Spinner />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</BaseCard>
|
||||
</RoomContext.Provider>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue