Merge pull request #4221 from matrix-org/bwindels/aliaslipstick

Fix: make alternative addresses UX less confusing
This commit is contained in:
Bruno Windels 2020-03-17 10:55:36 +00:00 committed by GitHub
commit e8c77543f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 125 additions and 56 deletions

View file

@ -20,14 +20,21 @@ limitations under the License.
} }
.mx_EditableItem { .mx_EditableItem {
display: flex;
margin-bottom: 5px; margin-bottom: 5px;
margin-left: 15px;
} }
.mx_EditableItem_delete { .mx_EditableItem_delete {
order: 3;
margin-right: 5px; margin-right: 5px;
cursor: pointer; cursor: pointer;
vertical-align: middle; vertical-align: middle;
width: 14px;
height: 14px;
mask-image: url('$(res)/img/feather-customised/cancel.svg');
mask-repeat: no-repeat;
background-color: $warning-color;
mask-size: 100%;
} }
.mx_EditableItem_email { .mx_EditableItem_email {
@ -36,12 +43,19 @@ limitations under the License.
.mx_EditableItem_promptText { .mx_EditableItem_promptText {
margin-right: 10px; margin-right: 10px;
order: 2;
} }
.mx_EditableItem_confirmBtn { .mx_EditableItem_confirmBtn {
margin-right: 5px; margin-right: 5px;
} }
.mx_EditableItem_item {
flex: auto 1 0;
order: 1;
}
.mx_EditableItemList_label { .mx_EditableItemList_label {
margin-bottom: 5px; margin-bottom: 5px;
} }

View file

@ -27,6 +27,20 @@ limitations under the License.
box-shadow: none; box-shadow: none;
} }
.mx_AliasSettings summary { .mx_AliasSettings {
summary {
cursor: pointer; cursor: pointer;
color: $accent-color;
font-weight: 600;
list-style: none;
// list-style doesn't do it for webkit
&::-webkit-details-marker {
display: none;
}
}
.mx_AliasSettings_localAliasHeader {
margin-top: 35px;
}
} }

View file

@ -47,11 +47,15 @@ limitations under the License.
.mx_SettingsTab_section { .mx_SettingsTab_section {
margin-bottom: 24px; margin-bottom: 24px;
}
.mx_SettingsTab_section .mx_SettingsFlag { .mx_SettingsFlag {
margin-right: 100px; margin-right: 100px;
margin-bottom: 10px; margin-bottom: 10px;
}
&.mx_SettingsTab_subsectionText .mx_SettingsFlag {
margin-right: 0px !important;
}
} }
.mx_SettingsTab_section .mx_SettingsFlag .mx_SettingsFlag_label { .mx_SettingsTab_section .mx_SettingsFlag .mx_SettingsFlag_label {

View file

@ -78,8 +78,7 @@ export class EditableItem extends React.Component {
return ( return (
<div className="mx_EditableItem"> <div className="mx_EditableItem">
<img src={require("../../../../res/img/feather-customised/cancel.svg")} width={14} height={14} <div onClick={this._onRemove} className="mx_EditableItem_delete" title={_t("Remove")} role="button" />
onClick={this._onRemove} className="mx_EditableItem_delete" alt={_t("Remove")} />
<span className="mx_EditableItem_item">{this.props.value}</span> <span className="mx_EditableItem_item">{this.props.value}</span>
</div> </div>
); );

View file

@ -25,6 +25,7 @@ import Field from "../elements/Field";
import ErrorDialog from "../dialogs/ErrorDialog"; import ErrorDialog from "../dialogs/ErrorDialog";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import RoomPublishSetting from "./RoomPublishSetting";
class EditableAliasesList extends EditableItemList { class EditableAliasesList extends EditableItemList {
constructor(props) { constructor(props) {
@ -97,6 +98,7 @@ export default class AliasSettings extends React.Component {
canonicalAlias: null, // #canonical:domain.tld canonicalAlias: null, // #canonical:domain.tld
updatingCanonicalAlias: false, updatingCanonicalAlias: false,
localAliasesLoading: false, localAliasesLoading: false,
detailsOpen: false,
}; };
if (props.canonicalAliasEvent) { if (props.canonicalAliasEvent) {
@ -267,6 +269,7 @@ export default class AliasSettings extends React.Component {
this.loadLocalAliases(); this.loadLocalAliases();
} }
} }
this.setState({detailsOpen: event.target.open});
}; };
onCanonicalAliasChange = (event) => { onCanonicalAliasChange = (event) => {
@ -346,16 +349,18 @@ export default class AliasSettings extends React.Component {
onItemAdded={this.onLocalAliasAdded} onItemAdded={this.onLocalAliasAdded}
onItemRemoved={this.onLocalAliasDeleted} onItemRemoved={this.onLocalAliasDeleted}
noItemsLabel={_t('This room has no local addresses')} noItemsLabel={_t('This room has no local addresses')}
placeholder={_t( placeholder={_t('Local address')}
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
)}
domain={localDomain} domain={localDomain}
/>); />);
} }
return ( return (
<div className='mx_AliasSettings'> <div className='mx_AliasSettings'>
<span className='mx_SettingsTab_subheading'>{_t("Published Addresses")}</span>
<p>{_t("Published addresses can be used by anyone on any server to join your room. " +
"To publish an address, it needs to be set as a local address first.")}</p>
{canonicalAliasSection} {canonicalAliasSection}
<RoomPublishSetting roomId={this.props.roomId} canSetCanonicalAlias={this.props.canSetCanonicalAlias} />
<datalist id="mx_AliasSettings_altRecommendations"> <datalist id="mx_AliasSettings_altRecommendations">
{this._getLocalNonAltAliases().map(alias => { {this._getLocalNonAltAliases().map(alias => {
return <option value={alias} key={alias} />; return <option value={alias} key={alias} />;
@ -372,14 +377,14 @@ export default class AliasSettings extends React.Component {
onItemAdded={this.onAltAliasAdded} onItemAdded={this.onAltAliasAdded}
onItemRemoved={this.onAltAliasDeleted} onItemRemoved={this.onAltAliasDeleted}
suggestionsListId="mx_AliasSettings_altRecommendations" suggestionsListId="mx_AliasSettings_altRecommendations"
itemsLabel={_t('Alternative addresses for this room:')} itemsLabel={_t('Other published addresses:')}
noItemsLabel={_t('This room has no alternative addresses')} noItemsLabel={_t('No other published addresses yet, add one below')}
placeholder={_t( placeholder={_t('New published address (e.g. #alias:server)')}
'New address (e.g. #foo:domain)',
)}
/> />
<span className='mx_SettingsTab_subheading mx_AliasSettings_localAliasHeader'>{_t("Local Addresses")}</span>
<p>{_t("Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)", {localDomain})}</p>
<details onToggle={this.onLocalAliasesToggled}> <details onToggle={this.onLocalAliasesToggled}>
<summary>{_t('Local addresses (unmoderated content)')}</summary> <summary>{ this.state.detailsOpen ? _t('Show less') : _t("Show more")}</summary>
{localAliasesList} {localAliasesList}
</details> </details>
</div> </div>

View file

@ -0,0 +1,60 @@
/*
Copyright 2020 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 LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import {_t} from "../../../languageHandler";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
export default class RoomPublishSetting extends React.PureComponent {
constructor(props) {
super(props);
this.state = {isRoomPublished: false};
}
onRoomPublishChange = (e) => {
const valueBefore = this.state.isRoomPublished;
const newValue = !valueBefore;
this.setState({isRoomPublished: newValue});
const client = MatrixClientPeg.get();
client.setRoomDirectoryVisibility(
this.props.roomId,
newValue ? 'public' : 'private',
).catch(() => {
// Roll back the local echo on the change
this.setState({isRoomPublished: valueBefore});
});
};
componentDidMount() {
const client = MatrixClientPeg.get();
client.getRoomDirectoryVisibility(this.props.roomId).then((result => {
this.setState({isRoomPublished: result.visibility === 'public'});
}));
}
render() {
const client = MatrixClientPeg.get();
return (<LabelledToggleSwitch value={this.state.isRoomPublished}
onChange={this.onRoomPublishChange}
disabled={!this.props.canSetCanonicalAlias}
label={_t("Publish this room to the public in %(domain)s's room directory?", {
domain: client.getDomain(),
})} />);
}
}

View file

@ -21,7 +21,6 @@ import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
import * as sdk from "../../../../.."; import * as sdk from "../../../../..";
import AccessibleButton from "../../../elements/AccessibleButton"; import AccessibleButton from "../../../elements/AccessibleButton";
import dis from "../../../../../dispatcher"; import dis from "../../../../../dispatcher";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
export default class GeneralRoomSettingsTab extends React.Component { export default class GeneralRoomSettingsTab extends React.Component {
@ -39,26 +38,6 @@ export default class GeneralRoomSettingsTab extends React.Component {
}; };
} }
componentWillMount() {
this.context.getRoomDirectoryVisibility(this.props.roomId).then((result => {
this.setState({isRoomPublished: result.visibility === 'public'});
}));
}
onRoomPublishChange = (e) => {
const valueBefore = this.state.isRoomPublished;
const newValue = !valueBefore;
this.setState({isRoomPublished: newValue});
this.context.setRoomDirectoryVisibility(
this.props.roomId,
newValue ? 'public' : 'private',
).catch(() => {
// Roll back the local echo on the change
this.setState({isRoomPublished: valueBefore});
});
};
_onLeaveClick = () => { _onLeaveClick = () => {
dis.dispatch({ dis.dispatch({
action: 'leave_room', action: 'leave_room',
@ -75,7 +54,6 @@ export default class GeneralRoomSettingsTab extends React.Component {
const room = client.getRoom(this.props.roomId); const room = client.getRoom(this.props.roomId);
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
const canActuallySetAliases = room.currentState.mayClientSendStateEvent("m.room.aliases", client);
const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client); const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", ''); const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", '');
const aliasEvents = room.currentState.getStateEvents("m.room.aliases"); const aliasEvents = room.currentState.getStateEvents("m.room.aliases");
@ -90,21 +68,13 @@ export default class GeneralRoomSettingsTab extends React.Component {
<RoomProfileSettings roomId={this.props.roomId} /> <RoomProfileSettings roomId={this.props.roomId} />
</div> </div>
<span className='mx_SettingsTab_subheading'>{_t("Room Addresses")}</span> <div className="mx_SettingsTab_heading">{_t("Room Addresses")}</div>
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'> <div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
<AliasSettings roomId={this.props.roomId} <AliasSettings roomId={this.props.roomId}
canSetCanonicalAlias={canSetCanonical} canSetAliases={canSetAliases} canSetCanonicalAlias={canSetCanonical} canSetAliases={canSetAliases}
canonicalAliasEvent={canonicalAliasEv} aliasEvents={aliasEvents} /> canonicalAliasEvent={canonicalAliasEv} aliasEvents={aliasEvents} />
</div> </div>
<div className='mx_SettingsTab_section'> <div className="mx_SettingsTab_heading">{_t("Other")}</div>
<LabelledToggleSwitch value={this.state.isRoomPublished}
onChange={this.onRoomPublishChange}
disabled={!canActuallySetAliases}
label={_t("Publish this room to the public in %(domain)s's room directory?", {
domain: client.getDomain(),
})} />
</div>
<span className='mx_SettingsTab_subheading'>{_t("Flair")}</span> <span className='mx_SettingsTab_subheading'>{_t("Flair")}</span>
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'> <div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
<RelatedGroupSettings roomId={room.roomId} <RelatedGroupSettings roomId={room.roomId}

View file

@ -840,7 +840,6 @@
"This room isnt bridging messages to any platforms. <a>Learn more.</a>": "This room isnt bridging messages to any platforms. <a>Learn more.</a>", "This room isnt bridging messages to any platforms. <a>Learn more.</a>": "This room isnt bridging messages to any platforms. <a>Learn more.</a>",
"Bridges": "Bridges", "Bridges": "Bridges",
"Room Addresses": "Room Addresses", "Room Addresses": "Room Addresses",
"Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?",
"URL Previews": "URL Previews", "URL Previews": "URL Previews",
"Uploaded sound": "Uploaded sound", "Uploaded sound": "Uploaded sound",
"Sounds": "Sounds", "Sounds": "Sounds",
@ -1163,11 +1162,14 @@
"Main address": "Main address", "Main address": "Main address",
"not specified": "not specified", "not specified": "not specified",
"This room has no local addresses": "This room has no local addresses", "This room has no local addresses": "This room has no local addresses",
"New address (e.g. #foo:%(localDomain)s)": "New address (e.g. #foo:%(localDomain)s)", "Local address": "Local address",
"Alternative addresses for this room:": "Alternative addresses for this room:", "Published Addresses": "Published Addresses",
"This room has no alternative addresses": "This room has no alternative addresses", "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.",
"New address (e.g. #foo:domain)": "New address (e.g. #foo:domain)", "Other published addresses:": "Other published addresses:",
"Local addresses (unmoderated content)": "Local addresses (unmoderated content)", "No other published addresses yet, add one below": "No other published addresses yet, add one below",
"New published address (e.g. #alias:server)": "New published address (e.g. #alias:server)",
"Local Addresses": "Local Addresses",
"Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)",
"Error updating flair": "Error updating flair", "Error updating flair": "Error updating flair",
"There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.", "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.",
"Invalid community ID": "Invalid community ID", "Invalid community ID": "Invalid community ID",
@ -1178,6 +1180,7 @@
"Room Name": "Room Name", "Room Name": "Room Name",
"Room Topic": "Room Topic", "Room Topic": "Room Topic",
"Room avatar": "Room avatar", "Room avatar": "Room avatar",
"Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?",
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.", "You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.", "You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
"URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.", "URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.",