Merge pull request #2229 from matrix-org/bwindels/roomsectionheadercleanup
Redesign: room section header tidbits
This commit is contained in:
commit
0992408930
4 changed files with 72 additions and 180 deletions
|
@ -15,25 +15,21 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_RoomSubList {
|
.mx_RoomSubList {
|
||||||
min-height: 80px;
|
min-height: 31px;
|
||||||
flex: 0;
|
flex: 0 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomSubList_hidden {
|
.mx_RoomSubList_nonEmpty {
|
||||||
min-height: unset;
|
min-height: 80px;
|
||||||
}
|
flex: 1;
|
||||||
|
|
||||||
.mx_RoomSubList_resizer {
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
background-color: $roomsublist-background;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomSubList_labelContainer {
|
.mx_RoomSubList_labelContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomSubList_label {
|
.mx_RoomSubList_label {
|
||||||
|
|
|
@ -23,6 +23,11 @@ limitations under the License.
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hide resize handles next to collapsed / empty sublists */
|
||||||
|
.mx_RoomList .mx_RoomSubList:not(.mx_RoomSubList_nonEmpty) + .mx_ResizeHandle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomList_expandButton {
|
.mx_RoomList_expandButton {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -50,14 +50,10 @@ const RoomSubList = React.createClass({
|
||||||
showSpinner: PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
showSpinner: PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
||||||
collapsed: PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
collapsed: PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
||||||
onHeaderClick: PropTypes.func,
|
onHeaderClick: PropTypes.func,
|
||||||
alwaysShowHeader: PropTypes.bool,
|
|
||||||
incomingCall: PropTypes.object,
|
incomingCall: PropTypes.object,
|
||||||
onShowMoreRooms: PropTypes.func,
|
|
||||||
searchFilter: PropTypes.string,
|
searchFilter: PropTypes.string,
|
||||||
emptyContent: PropTypes.node, // content shown if the list is empty
|
|
||||||
headerItems: PropTypes.node, // content shown in the sublist header
|
headerItems: PropTypes.node, // content shown in the sublist header
|
||||||
extraTiles: PropTypes.arrayOf(PropTypes.node), // extra elements added beneath tiles
|
extraTiles: PropTypes.arrayOf(PropTypes.node), // extra elements added beneath tiles
|
||||||
showEmpty: PropTypes.bool,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -71,11 +67,8 @@ const RoomSubList = React.createClass({
|
||||||
return {
|
return {
|
||||||
onHeaderClick: function() {
|
onHeaderClick: function() {
|
||||||
}, // NOP
|
}, // NOP
|
||||||
onShowMoreRooms: function() {
|
|
||||||
}, // NOP
|
|
||||||
extraTiles: [],
|
extraTiles: [],
|
||||||
isInvite: false,
|
isInvite: false,
|
||||||
showEmpty: true,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -138,7 +131,6 @@ const RoomSubList = React.createClass({
|
||||||
// The header isCollapsable, so the click is to be interpreted as collapse and truncation logic
|
// The header isCollapsable, so the click is to be interpreted as collapse and truncation logic
|
||||||
const isHidden = !this.state.hidden;
|
const isHidden = !this.state.hidden;
|
||||||
this.setState({hidden: isHidden});
|
this.setState({hidden: isHidden});
|
||||||
this.props.onShowMoreRooms();
|
|
||||||
this.props.onHeaderClick(isHidden);
|
this.props.onHeaderClick(isHidden);
|
||||||
} else {
|
} else {
|
||||||
// The header is stuck, so the click is to be interpreted as a scroll to the header
|
// The header is stuck, so the click is to be interpreted as a scroll to the header
|
||||||
|
@ -271,25 +263,21 @@ const RoomSubList = React.createClass({
|
||||||
const subListNotifCount = subListNotifications[0];
|
const subListNotifCount = subListNotifications[0];
|
||||||
const subListNotifHighlight = subListNotifications[1];
|
const subListNotifHighlight = subListNotifications[1];
|
||||||
|
|
||||||
const chevronClasses = classNames({
|
|
||||||
'mx_RoomSubList_chevron': true,
|
|
||||||
'mx_RoomSubList_chevronRight': this.state.hidden,
|
|
||||||
'mx_RoomSubList_chevronDown': !this.state.hidden,
|
|
||||||
});
|
|
||||||
|
|
||||||
const badgeClasses = classNames({
|
|
||||||
'mx_RoomSubList_badge': true,
|
|
||||||
'mx_RoomSubList_badgeHighlight': subListNotifHighlight,
|
|
||||||
});
|
|
||||||
|
|
||||||
let badge;
|
let badge;
|
||||||
if (subListNotifCount > 0) {
|
if (this.state.hidden) {
|
||||||
badge = <div className={badgeClasses} onClick={this._onNotifBadgeClick}>
|
const badgeClasses = classNames({
|
||||||
{ FormattingUtils.formatCount(subListNotifCount) }
|
'mx_RoomSubList_badge': true,
|
||||||
</div>;
|
'mx_RoomSubList_badgeHighlight': subListNotifHighlight,
|
||||||
} else if (this.props.isInvite) {
|
});
|
||||||
// no notifications but highlight anyway because this is an invite badge
|
if (subListNotifCount > 0) {
|
||||||
badge = <div className={badgeClasses} onClick={this._onInviteBadgeClick}>!</div>;
|
badge = <div className={badgeClasses} onClick={this._onNotifBadgeClick}>
|
||||||
|
{ FormattingUtils.formatCount(subListNotifCount) }
|
||||||
|
</div>;
|
||||||
|
} else if (this.props.isInvite) {
|
||||||
|
// no notifications but highlight anyway because this is an invite badge
|
||||||
|
badge = <div className={badgeClasses} onClick={this._onInviteBadgeClick}>!</div>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When collapsed, allow a long hover on the header to show user
|
// When collapsed, allow a long hover on the header to show user
|
||||||
|
@ -323,12 +311,22 @@ const RoomSubList = React.createClass({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabindex = this.props.searchFilter === "" ? "0" : "-1";
|
const len = this.state.sortedList.length + this.props.extraTiles.length;
|
||||||
|
let chevron;
|
||||||
|
if (len) {
|
||||||
|
const chevronClasses = classNames({
|
||||||
|
'mx_RoomSubList_chevron': true,
|
||||||
|
'mx_RoomSubList_chevronRight': this.state.hidden,
|
||||||
|
'mx_RoomSubList_chevronDown': !this.state.hidden,
|
||||||
|
});
|
||||||
|
chevron = (<div className={chevronClasses}></div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabindex = this.props.searchFilter === "" ? "0" : "-1";
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
|
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
|
||||||
<AccessibleButton onClick={ this.onClick } className="mx_RoomSubList_label" tabIndex={tabindex}>
|
<AccessibleButton onClick={ this.onClick } className="mx_RoomSubList_label" tabIndex={tabindex}>
|
||||||
<div className={chevronClasses}></div>
|
{ chevron }
|
||||||
{ this.props.collapsed ? '' : this.props.label }
|
{ this.props.collapsed ? '' : this.props.label }
|
||||||
{ badge }
|
{ badge }
|
||||||
{ incomingCall }
|
{ incomingCall }
|
||||||
|
@ -339,64 +337,43 @@ const RoomSubList = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
let content;
|
|
||||||
|
|
||||||
if (this.props.showEmpty) {
|
|
||||||
// this is new behaviour with still controversial UX in that in hiding RoomSubLists the drop zones for DnD
|
|
||||||
// are also gone so when filtering users can't DnD rooms to some tags but is a lot cleaner otherwise.
|
|
||||||
if (this.state.sortedList.length === 0 && !this.props.searchFilter && this.props.extraTiles.length === 0) {
|
|
||||||
content = this.props.emptyContent;
|
|
||||||
} else {
|
|
||||||
content = this.makeRoomTiles();
|
|
||||||
content.push(...this.props.extraTiles);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.state.sortedList.length === 0 && this.props.extraTiles.length === 0) {
|
|
||||||
// if no search filter is applied and there is a placeholder defined then show it, otherwise show nothing
|
|
||||||
if (!this.props.searchFilter && this.props.emptyContent) {
|
|
||||||
content = this.props.emptyContent;
|
|
||||||
} else {
|
|
||||||
// don't show an empty sublist
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content = this.makeRoomTiles();
|
|
||||||
content.push(...this.props.extraTiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const len = this.state.sortedList.length + this.props.extraTiles.length;
|
const len = this.state.sortedList.length + this.props.extraTiles.length;
|
||||||
|
|
||||||
if (len) {
|
if (len) {
|
||||||
|
const subListClasses = classNames({
|
||||||
|
"mx_RoomSubList": true,
|
||||||
|
"mx_RoomSubList_nonEmpty": len && !this.state.hidden,
|
||||||
|
});
|
||||||
if (this.state.hidden) {
|
if (this.state.hidden) {
|
||||||
return <div className={["mx_RoomSubList", "mx_RoomSubList_hidden"]}>
|
return <div className={subListClasses}>
|
||||||
{this._getHeaderJsx()}
|
{this._getHeaderJsx()}
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
const heightEstimation = (len * 40) + 31;
|
const heightEstimation = (len * 40) + 31;
|
||||||
const style = {
|
const style = {
|
||||||
flexBasis: `${heightEstimation}px`,
|
flexGrow: `${heightEstimation}`,
|
||||||
maxHeight: `${heightEstimation}px`,
|
maxHeight: `${heightEstimation}px`,
|
||||||
};
|
};
|
||||||
const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper");
|
const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper");
|
||||||
return <div className={"mx_RoomSubList"} style={style}>
|
const tiles = this.makeRoomTiles();
|
||||||
|
tiles.push(...this.props.extraTiles);
|
||||||
|
return <div className={subListClasses} style={style}>
|
||||||
{this._getHeaderJsx()}
|
{this._getHeaderJsx()}
|
||||||
<GeminiScrollbarWrapper>
|
<GeminiScrollbarWrapper>
|
||||||
{ content }
|
{ tiles }
|
||||||
</GeminiScrollbarWrapper>
|
</GeminiScrollbarWrapper>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
if (this.props.showSpinner) {
|
let content;
|
||||||
|
if (this.props.showSpinner && !this.state.hidden) {
|
||||||
content = <Loader />;
|
content = <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomSubList">
|
<div className="mx_RoomSubList">
|
||||||
{this.props.alwaysShowHeader ? this._getHeaderJsx() : undefined}
|
{ this._getHeaderJsx() }
|
||||||
{ this.state.hidden ? undefined : content }
|
{ content }
|
||||||
<div className="mx_RoomSubList_resizer"></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,71 +406,6 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onShowMoreRooms: function() {
|
|
||||||
// kick gemini in the balls to get it to wake up
|
|
||||||
// XXX: uuuuuuugh.
|
|
||||||
if (!this._gemScroll) return;
|
|
||||||
this._gemScroll.forceUpdate();
|
|
||||||
},
|
|
||||||
|
|
||||||
_getEmptyContent: function(section) {
|
|
||||||
if (this.state.selectedTags.length > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget');
|
|
||||||
|
|
||||||
if (this.props.collapsed) {
|
|
||||||
return <RoomDropTarget label="" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StartChatButton = sdk.getComponent('elements.StartChatButton');
|
|
||||||
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
|
|
||||||
const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton');
|
|
||||||
|
|
||||||
let tip = null;
|
|
||||||
|
|
||||||
switch (section) {
|
|
||||||
case 'im.vector.fake.direct':
|
|
||||||
tip = <div className="mx_RoomList_emptySubListTip">
|
|
||||||
{ _t(
|
|
||||||
"Press <StartChatButton> to start a chat with someone",
|
|
||||||
{},
|
|
||||||
{ 'StartChatButton': <StartChatButton size="16" callout={true} /> },
|
|
||||||
) }
|
|
||||||
</div>;
|
|
||||||
break;
|
|
||||||
case 'im.vector.fake.recent':
|
|
||||||
tip = <div className="mx_RoomList_emptySubListTip">
|
|
||||||
{ _t(
|
|
||||||
"You're not in any rooms yet! Press <CreateRoomButton> to make a room or"+
|
|
||||||
" <RoomDirectoryButton> to browse the directory",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'CreateRoomButton': <CreateRoomButton size="16" callout={true} />,
|
|
||||||
'RoomDirectoryButton': <RoomDirectoryButton size="16" callout={true} />,
|
|
||||||
},
|
|
||||||
) }
|
|
||||||
</div>;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tip) {
|
|
||||||
return <div className="mx_RoomList_emptySubListTip_container">
|
|
||||||
{ tip }
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't want to display drop targets if there are no room tiles to drag'n'drop
|
|
||||||
if (this.state.totalRoomCount === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const labelText = phraseForSection(section);
|
|
||||||
|
|
||||||
return <RoomDropTarget label={labelText} />;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getHeaderItems: function(section) {
|
_getHeaderItems: function(section) {
|
||||||
const StartChatButton = sdk.getComponent('elements.StartChatButton');
|
const StartChatButton = sdk.getComponent('elements.StartChatButton');
|
||||||
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
|
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
|
||||||
|
@ -508,28 +443,21 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
const RoomSubList = sdk.getComponent('structures.RoomSubList');
|
const RoomSubList = sdk.getComponent('structures.RoomSubList');
|
||||||
|
|
||||||
// XXX: we can't detect device-level (localStorage) settings onChange as the SettingsStore does not notify
|
const mapProps = (subListsProps) => {
|
||||||
// so checking on every render is the sanest thing at this time.
|
|
||||||
const showEmpty = SettingsStore.getValue('RoomSubList.showEmpty');
|
|
||||||
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
function mapProps(subListsProps) {
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
collapsed: self.props.collapsed,
|
collapsed: this.props.collapsed,
|
||||||
searchFilter: self.props.searchFilter,
|
searchFilter: this.props.searchFilter,
|
||||||
onShowMoreRooms: self.onShowMoreRooms,
|
incomingCall: this.state.incomingCall,
|
||||||
showEmpty: showEmpty,
|
|
||||||
incomingCall: self.state.incomingCall,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subListsProps = subListsProps.filter((props => {
|
||||||
|
const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0);
|
||||||
|
return len !== 0 || props.onAddRoom;
|
||||||
|
}));
|
||||||
|
|
||||||
return subListsProps.reduce((components, props, i) => {
|
return subListsProps.reduce((components, props, i) => {
|
||||||
props = Object.assign({}, defaultProps, props);
|
props = Object.assign({}, defaultProps, props);
|
||||||
const isLast = i === subListsProps.length - 1;
|
const isLast = i === subListsProps.length - 1;
|
||||||
const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0);
|
|
||||||
// empty and no add button? dont render
|
|
||||||
if (!len && !props.onAddRoom) {
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
const {key, label, ... otherProps} = props;
|
const {key, label, ... otherProps} = props;
|
||||||
const chosenKey = key || label;
|
const chosenKey = key || label;
|
||||||
|
|
||||||
|
@ -548,83 +476,69 @@ module.exports = React.createClass({
|
||||||
let subLists = [
|
let subLists = [
|
||||||
{
|
{
|
||||||
list: [],
|
list: [],
|
||||||
extraTiles: this._makeGroupInviteTiles(self.props.searchFilter),
|
extraTiles: this._makeGroupInviteTiles(this.props.searchFilter),
|
||||||
label: _t('Community Invites'),
|
label: _t('Community Invites'),
|
||||||
order: "recent",
|
order: "recent",
|
||||||
isInvite: true,
|
isInvite: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['im.vector.fake.invite'],
|
list: this.state.lists['im.vector.fake.invite'],
|
||||||
label: _t('Invites'),
|
label: _t('Invites'),
|
||||||
order: "recent",
|
order: "recent",
|
||||||
isInvite: true,
|
isInvite: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['m.favourite'],
|
list: this.state.lists['m.favourite'],
|
||||||
label: _t('Favourites'),
|
label: _t('Favourites'),
|
||||||
tagName: "m.favourite",
|
tagName: "m.favourite",
|
||||||
emptyContent: this._getEmptyContent('m.favourite'),
|
|
||||||
order: "manual",
|
order: "manual",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['im.vector.fake.direct'],
|
list: this.state.lists['im.vector.fake.direct'],
|
||||||
label: _t('People'),
|
label: _t('People'),
|
||||||
tagName: "im.vector.fake.direct",
|
tagName: "im.vector.fake.direct",
|
||||||
emptyContent: this._getEmptyContent('im.vector.fake.direct'),
|
|
||||||
headerItems: this._getHeaderItems('im.vector.fake.direct'),
|
headerItems: this._getHeaderItems('im.vector.fake.direct'),
|
||||||
order: "recent",
|
order: "recent",
|
||||||
alwaysShowHeader: true,
|
|
||||||
onAddRoom: () => {dis.dispatch({action: 'view_create_chat'})},
|
onAddRoom: () => {dis.dispatch({action: 'view_create_chat'})},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['im.vector.fake.recent'],
|
list: this.state.lists['im.vector.fake.recent'],
|
||||||
label: _t('Rooms'),
|
label: _t('Rooms'),
|
||||||
emptyContent: this._getEmptyContent('im.vector.fake.recent'),
|
|
||||||
headerItems: this._getHeaderItems('im.vector.fake.recent'),
|
headerItems: this._getHeaderItems('im.vector.fake.recent'),
|
||||||
order: "recent",
|
order: "recent",
|
||||||
onAddRoom: () => {dis.dispatch({action: 'view_create_room'})},
|
onAddRoom: () => {dis.dispatch({action: 'view_create_room'})},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const tagSubLists = Object.keys(self.state.lists)
|
const tagSubLists = Object.keys(this.state.lists)
|
||||||
.filter((tagName) => {
|
.filter((tagName) => {
|
||||||
return !tagName.match(STANDARD_TAGS_REGEX);
|
return !tagName.match(STANDARD_TAGS_REGEX);
|
||||||
}).map((tagName) => {
|
}).map((tagName) => {
|
||||||
return {
|
return {
|
||||||
list: self.state.lists[tagName],
|
list: this.state.lists[tagName],
|
||||||
key: tagName,
|
key: tagName,
|
||||||
label: labelForTagName(tagName),
|
label: labelForTagName(tagName),
|
||||||
tagName: tagName,
|
tagName: tagName,
|
||||||
emptyContent: this._getEmptyContent(tagName),
|
|
||||||
order: "manual",
|
order: "manual",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
subLists = subLists.concat(tagSubLists);
|
subLists = subLists.concat(tagSubLists);
|
||||||
subLists = subLists.concat([
|
subLists = subLists.concat([
|
||||||
{
|
{
|
||||||
list: self.state.lists['m.lowpriority'],
|
list: this.state.lists['m.lowpriority'],
|
||||||
label: _t('Low priority'),
|
label: _t('Low priority'),
|
||||||
tagName: "m.lowpriority",
|
tagName: "m.lowpriority",
|
||||||
emptyContent: this._getEmptyContent('m.lowpriority'),
|
|
||||||
order: "recent",
|
order: "recent",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['im.vector.fake.archived'],
|
list: this.state.lists['im.vector.fake.archived'],
|
||||||
emptyContent: self.props.collapsed ?
|
|
||||||
null :
|
|
||||||
<div className="mx_RoomList_emptySubListTip_container">
|
|
||||||
<div className="mx_RoomList_emptySubListTip">
|
|
||||||
{ _t('You have no historical rooms') }
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
label: _t('Historical'),
|
label: _t('Historical'),
|
||||||
order: "recent",
|
order: "recent",
|
||||||
alwaysShowHeader: true,
|
|
||||||
startAsHidden: true,
|
startAsHidden: true,
|
||||||
showSpinner: self.state.isLoadingLeftRooms,
|
showSpinner: this.state.isLoadingLeftRooms,
|
||||||
onHeaderClick: self.onArchivedHeaderClick,
|
onHeaderClick: this.onArchivedHeaderClick,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
list: self.state.lists['m.server_notice'],
|
list: this.state.lists['m.server_notice'],
|
||||||
label: _t('System Alerts'),
|
label: _t('System Alerts'),
|
||||||
tagName: "m.lowpriority",
|
tagName: "m.lowpriority",
|
||||||
order: "recent",
|
order: "recent",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue