From 5c582037ceb6522c4f1344c693af6a6a7cda5041 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 10 Mar 2020 23:11:48 +0000 Subject: [PATCH 01/19] Tweak padding to match Figma Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 6 +++--- src/components/structures/RoomDirectory.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 5ae8df7176..241c921f20 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -46,8 +46,8 @@ limitations under the License. .mx_RoomDirectory_listheader { display: flex; - margin-top: 12px; - margin-bottom: 12px; + margin-top: 13px; + margin-bottom: 13px; } .mx_RoomDirectory_searchbox { @@ -148,7 +148,7 @@ limitations under the License. padding: 0; } -.mx_RoomDirectory p { +.mx_RoomDirectory > span { font-size: 14px; margin-top: 0; diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index dd089a9776..3c3d67578e 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -628,7 +628,7 @@ export default createReactClass({ title={_t("Explore rooms")} >
-

{explanation}

+ {explanation}
{listHeader} {content} From 86e53ea2c31f99a60a6d0113584400b7fa87aff4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:02:50 +0000 Subject: [PATCH 02/19] Initial attempt to redesign explore servers in room directory Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 3 +- res/css/views/directory/_NetworkDropdown.scss | 180 +++++--- .../views/elements/_DirectorySearchBox.scss | 1 - src/components/structures/MatrixChat.js | 5 +- src/components/structures/RoomDirectory.js | 44 +- .../views/dialogs/TextInputDialog.js | 11 +- .../views/directory/NetworkDropdown.js | 383 +++++++++--------- src/i18n/strings/en_EN.json | 9 + src/settings/Settings.js | 4 + 9 files changed, 362 insertions(+), 278 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 241c921f20..d6ae0bb739 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -45,7 +46,7 @@ limitations under the License. } .mx_RoomDirectory_listheader { - display: flex; + display: block; margin-top: 13px; margin-bottom: 13px; } diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index d402f6c48f..3dc3a99dd4 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -15,70 +16,143 @@ limitations under the License. */ .mx_NetworkDropdown { + height: 32px; position: relative; -} + width: max-content; + padding-right: 32px; + margin-left: auto; + margin-right: 9px; + margin-top: 12px; -.mx_NetworkDropdown_input { - position: relative; - border-radius: 3px; - border: 1px solid $strong-input-border-color; - font-weight: 300; - font-size: 13px; - user-select: none; -} - -.mx_NetworkDropdown_arrow { - border-color: $primary-fg-color transparent transparent; - border-style: solid; - border-width: 5px 5px 0; - display: block; - height: 0; - position: absolute; - right: 10px; - top: 16px; - width: 0; -} - -.mx_NetworkDropdown_networkoption { - height: 37px; - line-height: 37px; - padding-left: 8px; - padding-right: 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.mx_NetworkDropdown_networkoption img { - margin: 5px; - width: 25px; - vertical-align: middle; -} - -input.mx_NetworkDropdown_networkoption, input.mx_NetworkDropdown_networkoption:focus { - border: 0; - padding-top: 0; - padding-bottom: 0; + .mx_AccessibleButton { + width: max-content; + } } .mx_NetworkDropdown_menu { - position: absolute; - left: -1px; - right: -1px; - top: 100%; - z-index: 2; + //position: absolute; + //left: -1px; + //right: -1px; + //top: 100%; + //z-index: 2; + width: 204px; margin: 0; - padding: 0px; - border-radius: 3px; + box-sizing: border-box; + border-radius: 4px; border: 1px solid $accent-color; background-color: $primary-bg-color; } -.mx_NetworkDropdown_menu .mx_NetworkDropdown_networkoption:hover { - background-color: $focus-bg-color; -} - .mx_NetworkDropdown_menu_network { font-weight: bold; } +.mx_NetworkDropdown_server { + padding: 12px 0; + border-bottom: 1px solid $input-darker-fg-color; + + .mx_NetworkDropdown_server_title { + padding: 0 10px; + font-size: 15px; + font-weight: 600; + line-height: 20px; + margin-bottom: 4px; + + // remove server button + .mx_AccessibleButton { + position: absolute; + display: inline; + right: 0; + + &::before { + content: ""; + position: absolute; + width: 16px; + height: 16px; + right: 12px; + top: 4px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/x.svg'); + background-color: $notice-primary-color; + } + } + } + + .mx_NetworkDropdown_server_subtitle { + padding: 0 10px; + font-size: 10px; + line-height: 14px; + margin-top: -4px; + margin-bottom: 4px; + color: $muted-fg-color; + } + + .mx_NetworkDropdown_server_network { + font-size: 12px; + line-height: 16px; + padding: 4px 10px; + cursor: pointer; + position: relative; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + &[aria-checked=true]::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + right: 10px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/check.svg'); + background-color: $input-valid-border-color; + } + } +} + +.mx_NetworkDropdown_server_add, +.mx_NetworkDropdown_server_network { + &:hover { + background-color: $header-panel-bg-color; + } +} + +.mx_NetworkDropdown_server_add { + padding: 16px 10px 16px 32px; + position: relative; + + &::before { + content: ""; + position: absolute; + width: 16px; + height: 16px; + left: 7px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/plus.svg'); + background-color: $muted-fg-color; + } +} + +.mx_NetworkDropdown_handle { + position: relative; + + &::after { + content: ""; + position: absolute; + width: 24px; + height: 24px; + right: -28px; // - (24 + 4) + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + background-color: $primary-fg-color; + } +} diff --git a/res/css/views/elements/_DirectorySearchBox.scss b/res/css/views/elements/_DirectorySearchBox.scss index ef944f6fa0..75ef3fbabd 100644 --- a/res/css/views/elements/_DirectorySearchBox.scss +++ b/res/css/views/elements/_DirectorySearchBox.scss @@ -18,7 +18,6 @@ limitations under the License. display: flex; padding-left: 9px; padding-right: 9px; - margin: 0 5px 0 0 !important; } .mx_DirectorySearchBox_joinButton { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a0b9a8fe57..0099af8398 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -600,9 +600,8 @@ export default createReactClass({ break; case 'view_room_directory': { const RoomDirectory = sdk.getComponent("structures.RoomDirectory"); - Modal.createTrackedDialog('Room directory', '', RoomDirectory, { - config: this.props.config, - }, 'mx_RoomDirectory_dialogWrapper'); + Modal.createTrackedDialog('Room directory', '', RoomDirectory, {}, + 'mx_RoomDirectory_dialogWrapper', false, true); // View the welcome or home page if we need something to look at this._viewSomethingBehindModal(); diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 3c3d67578e..ddc172fca7 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -28,6 +28,7 @@ import { _t } from '../../languageHandler'; import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; import Analytics from '../../Analytics'; import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo"; +import {ALL_ROOMS} from "../views/directory/NetworkDropdown"; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 160; @@ -40,25 +41,17 @@ export default createReactClass({ displayName: 'RoomDirectory', propTypes: { - config: PropTypes.object, onFinished: PropTypes.func.isRequired, }, - getDefaultProps: function() { - return { - config: {}, - }; - }, - getInitialState: function() { return { publicRooms: [], loading: true, protocolsLoading: true, error: null, - instanceId: null, - includeAll: false, - roomServer: null, + instanceId: undefined, + roomServer: MatrixClientPeg.getHomeserverName(), filterString: null, }; }, @@ -98,6 +91,10 @@ export default createReactClass({ }); }, + componentDidMount: function() { + this.refreshRoomList(); + }, + componentWillUnmount: function() { if (this.filterTimeout) { clearTimeout(this.filterTimeout); @@ -130,10 +127,10 @@ export default createReactClass({ if (my_server != MatrixClientPeg.getHomeserverName()) { opts.server = my_server; } - if (this.state.instanceId) { - opts.third_party_instance_id = this.state.instanceId; - } else if (this.state.includeAll) { + if (this.state.instanceId === ALL_ROOMS) { opts.include_all_networks = true; + } else if (this.state.instanceId) { + opts.third_party_instance_id = this.state.instanceId; } if (this.nextBatch) opts.since = this.nextBatch; if (my_filter_string) opts.filter = { generic_search_term: my_filter_string }; @@ -247,7 +244,7 @@ export default createReactClass({ } }, - onOptionChange: function(server, instanceId, includeAll) { + onOptionChange: function(server, instanceId) { // clear next batch so we don't try to load more rooms this.nextBatch = null; this.setState({ @@ -257,7 +254,6 @@ export default createReactClass({ publicRooms: [], roomServer: server, instanceId: instanceId, - includeAll: includeAll, error: null, }, this.refreshRoomList); // We also refresh the room list each time even though this @@ -305,7 +301,7 @@ export default createReactClass({ onJoinFromSearchClick: function(alias) { // If we don't have a particular instance id selected, just show that rooms alias - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { // If the user specified an alias without a domain, add on whichever server is selected // in the dropdown if (alias.indexOf(':') == -1) { @@ -587,7 +583,7 @@ export default createReactClass({ } let placeholder = _t('Find a room…'); - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { placeholder = _t("Find a room… (e.g. %(exampleRoom)s)", {exampleRoom: "#example:" + this.state.roomServer}); } else if (instance_expected_field_type) { placeholder = instance_expected_field_type.placeholder; @@ -604,10 +600,18 @@ export default createReactClass({ listHeader =
+ -
; } const explanation = diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 0ffc072cc0..4b21e8206e 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -28,9 +28,11 @@ export default createReactClass({ PropTypes.string, ]), value: PropTypes.string, + placeholder: PropTypes.string, button: PropTypes.string, focus: PropTypes.bool, onFinished: PropTypes.func.isRequired, + hasCancel: PropTypes.bool, }, getDefaultProps: function() { @@ -39,6 +41,7 @@ export default createReactClass({ value: "", description: "", focus: true, + hasCancel: true, }; }, @@ -80,13 +83,17 @@ export default createReactClass({ className="mx_TextInputDialog_input" defaultValue={this.props.value} autoFocus={this.props.focus} + placeholder={this.props.placeholder} size="64" />
- + onCancel={this.onCancel} + hasCancel={this.props.hasCancel} + /> ); }, diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index cb6a015d86..229f80ef29 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +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. @@ -17,239 +18,225 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; + import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; +import {ContextMenu, useContextMenu, ContextMenuButton, MenuItemRadio, MenuItem} from "../../structures/ContextMenu"; +import {_t} from "../../../languageHandler"; +import SdkConfig from "../../../SdkConfig"; +import {useSettingValue} from "../../../hooks/useSettings"; +import * as sdk from "../../../index"; +import Modal from "../../../Modal"; +import SettingsStore from "../../../settings/SettingsStore"; +import AccessibleButton from "../elements/AccessibleButton"; -const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg"); +export const ALL_ROOMS = Symbol("ALL_ROOMS"); -export default class NetworkDropdown extends React.Component { - constructor(props) { - super(props); +const SETTING_NAME = "room_directory_servers"; - this.dropdownRootElement = null; - this.ignoreEvent = null; +const inPlaceOf = (elementRect) => ({ + right: window.innerWidth - elementRect.right, + top: elementRect.top, + chevronOffset: 0, + chevronFace: "none", +}); - this.onInputClick = this.onInputClick.bind(this); - this.onRootClick = this.onRootClick.bind(this); - this.onDocumentClick = this.onDocumentClick.bind(this); - this.onMenuOptionClick = this.onMenuOptionClick.bind(this); - this.onInputKeyUp = this.onInputKeyUp.bind(this); - this.collectRoot = this.collectRoot.bind(this); - this.collectInputTextBox = this.collectInputTextBox.bind(this); +// This dropdown sources homeservers from three places: +// + your currently connected homeserver +// + homeservers in config.json["roomDirectory"] +// + homeservers in SettingsStore["room_directory_servers"] +// if a server exists in multiple, only keep the top-most entry. - this.inputTextBox = null; +const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, selectedInstanceId}) => { + const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); + const userDefinedServers = useSettingValue(SETTING_NAME); - const server = MatrixClientPeg.getHomeserverName(); - this.state = { - expanded: false, - selectedServer: server, - selectedInstanceId: null, - includeAllNetworks: false, + const handlerFactory = (server, instanceId) => { + return () => { + onOptionChange(server, instanceId); + closeMenu(); }; - } + }; - componentWillMount() { - // Listen for all clicks on the document so we can close the - // menu when the user clicks somewhere else - document.addEventListener('click', this.onDocumentClick, false); + // we either show the button or the dropdown in its place. + let content; + if (menuDisplayed) { + const config = SdkConfig.get(); + const roomDirectory = config.roomDirectory || {}; - // fire this now so the defaults can be set up - const {selectedServer, selectedInstanceId, includeAllNetworks} = this.state; - this.props.onOptionChange(selectedServer, selectedInstanceId, includeAllNetworks); - } + const hsName = MatrixClientPeg.getHomeserverName(); + const configServers = new Set(roomDirectory.servers); - componentWillUnmount() { - document.removeEventListener('click', this.onDocumentClick, false); - } - - componentDidUpdate() { - if (this.state.expanded && this.inputTextBox) { - this.inputTextBox.focus(); - } - } - - onDocumentClick(ev) { - // Close the dropdown if the user clicks anywhere that isn't - // within our root element - if (ev !== this.ignoreEvent) { - this.setState({ - expanded: false, - }); - } - } - - onRootClick(ev) { - // This captures any clicks that happen within our elements, - // such that we can then ignore them when they're seen by the - // click listener on the document handler, ie. not close the - // dropdown immediately after opening it. - // NB. We can't just stopPropagation() because then the event - // doesn't reach the React onClick(). - this.ignoreEvent = ev; - } - - onInputClick(ev) { - this.setState({ - expanded: !this.state.expanded, - }); - ev.preventDefault(); - } - - onMenuOptionClick(server, instance, includeAll) { - this.setState({ - expanded: false, - selectedServer: server, - selectedInstanceId: instance ? instance.instance_id : null, - includeAllNetworks: includeAll, - }); - this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll); - } - - onInputKeyUp(e) { - if (e.key === 'Enter') { - this.setState({ - expanded: false, - selectedServer: e.target.value, - selectedNetwork: null, - includeAllNetworks: false, - }); - this.props.onOptionChange(e.target.value, null); - } - } - - collectRoot(e) { - if (this.dropdownRootElement) { - this.dropdownRootElement.removeEventListener('click', this.onRootClick, false); - } - if (e) { - e.addEventListener('click', this.onRootClick, false); - } - this.dropdownRootElement = e; - } - - collectInputTextBox(e) { - this.inputTextBox = e; - } - - _getMenuOptions() { - const options = []; - const roomDirectory = this.props.config.roomDirectory || {}; - - let servers = []; - if (roomDirectory.servers) { - servers = servers.concat(roomDirectory.servers); - } - - if (!servers.includes(MatrixClientPeg.getHomeserverName())) { - servers.unshift(MatrixClientPeg.getHomeserverName()); - } + // configured servers take preference over user-defined ones, if one occurs in both ignore the latter one. + const removableServers = new Set(userDefinedServers.filter(s => !configServers.has(s) && s !== hsName)); + const servers = [ + // we always show our connected HS, this takes precedence over it being configured or user-defined + hsName, + ...Array.from(configServers).filter(s => s !== hsName).sort(), + ...Array.from(removableServers).sort(), + ]; // For our own HS, we can use the instance_ids given in the third party protocols // response to get the server to filter the room list by network for us. // We can't get thirdparty protocols for remote server yet though, so for those // we can only show the default room list. - for (const server of servers) { - options.push(this._makeMenuOption(server, null, true)); - if (server === MatrixClientPeg.getHomeserverName()) { - options.push(this._makeMenuOption(server, null, false)); - if (this.props.protocols) { - for (const proto of Object.keys(this.props.protocols)) { - if (!this.props.protocols[proto].instances) continue; + const options = servers.map(server => { + const serverSelected = server === selectedServerName; + const entries = []; - const sortedInstances = this.props.protocols[proto].instances; - sortedInstances.sort(function(x, y) { - const a = x.desc; - const b = y.desc; - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } - }); - - for (const instance of sortedInstances) { - if (!instance.instance_id) continue; - options.push(this._makeMenuOption(server, instance, false)); - } - } - } + const protocolsList = server === hsName ? Object.values(protocols) : []; + if (protocolsList.length > 0) { + // add a fake protocol with the ALL_ROOMS symbol + protocolsList.push({ + instances: [{ + instance_id: ALL_ROOMS, + desc: _t("All rooms"), + }], + }); } - } - return options; - } + protocolsList.forEach(({instances=[]}) => { + [...instances].sort((b, a) => { + return a.desc.localeCompare(b.desc); + }).forEach(({desc, instance_id: instanceId}) => { + entries.push( + + { desc } + ); + }); + }); - _makeMenuOption(server, instance, includeAll, handleClicks) { - if (handleClicks === undefined) handleClicks = true; + let subtitle; + if (server === hsName) { + subtitle = ( +
+ {_t("Your server")} +
+ ); + } - let icon; - let name; - let key; + let removeButton; + if (removableServers.has(server)) { + const onClick = async () => { + closeMenu(); + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const {finished} = Modal.createTrackedDialog("Network Dropdown", "Remove server", QuestionDialog, { + title: _t("Are you sure?"), + description: _t("Are you sure you want to remove %(serverName)s", { + serverName: server, + }, { + b: serverName => { serverName }, + }), + button: _t("Remove"), + }); - if (!instance && includeAll) { - key = server; - name = server; - } else if (!instance) { - key = server + '_all'; - name = 'Matrix'; - icon = ; - } else { - key = server + '_inst_' + instance.instance_id; - const imgUrl = instance.icon ? - MatrixClientPeg.get().mxcUrlToHttp(instance.icon, 25, 25, 'crop', true) : - DEFAULT_ICON_URL; - icon = ; - name = instance.desc; - } + const [ok] = await finished; + if (!ok) return; - const clickHandler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null; + // delete from setting + await SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); - return
- {icon} - {name} -
; - } + // the selected server is being removed, reset to our HS + if (serverSelected === server) { + onOptionChange(hsName, undefined); + } + }; + removeButton = ; + } - render() { - let currentValue; + return ( +
+
+ { server } + { removeButton } +
+ { subtitle } - let menu; - if (this.state.expanded) { - const menuOptions = this._getMenuOptions(); - menu =
- {menuOptions} -
; - currentValue = ; - } else { - const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId); - currentValue = this._makeMenuOption( - this.state.selectedServer, instance, this.state.includeAllNetworks, false, + + {_t("Matrix")} + + { entries } +
); + }); + + const onClick = async () => { + closeMenu(); + const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); + const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, { + title: _t("Add a new server"), + description: _t("Enter the address of a new server you want to explore."), + button: _t("Add"), + hasCancel: false, + placeholder: _t("Server address"), + }); + + const [ok, newServer] = await finished; + if (!ok) return; + + if (!userDefinedServers.includes(newServer)) { + const servers = [...userDefinedServers, newServer]; + await SettingsStore.setValue(SETTING_NAME, null, "account", servers); + } + + onOptionChange(newServer); // change filter to the new server + }; + + const buttonRect = handle.current.getBoundingClientRect(); + content = +
+ {options} + + {_t("Add a new server...")} + +
+
; + } else { + let currentValue; + if (selectedInstanceId === ALL_ROOMS) { + currentValue = _t("All rooms"); + } else if (selectedInstanceId) { + const instance = instanceForInstanceId(protocols, selectedInstanceId); + currentValue = _t("%(networkName)s rooms", { + networkName: instance.desc, + }); + } else { + currentValue = _t("Matrix rooms"); } - return
-
+ content = + {currentValue} - - {menu} -
-
; + + ({selectedServerName}) + + ; } -} + + return
+ {content} +
; +}; NetworkDropdown.propTypes = { onOptionChange: PropTypes.func.isRequired, protocols: PropTypes.object, - // The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown - config: PropTypes.object, }; -NetworkDropdown.defaultProps = { - protocols: {}, - config: {}, -}; +export default NetworkDropdown; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2f8f5c48ad..a5763fe5c5 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,6 +1437,15 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "All rooms": "All rooms", + "Your server": "Your server", + "Matrix": "Matrix", + "Add a new server": "Add a new server", + "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", + "Server address": "Server address", + "Add a new server...": "Add a new server...", + "%(networkName)s rooms": "%(networkName)s rooms", + "Matrix rooms": "Matrix rooms", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index b77fb392e9..8024c411f7 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -324,6 +324,10 @@ export const SETTINGS = { supportedLevels: ['account'], default: [], }, + "room_directory_servers": { + supportedLevels: ['account'], + default: [], + }, "integrationProvisioning": { supportedLevels: ['account'], default: true, From dd4dc054aef404745299eb5838d6707eeb532360 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:06:41 +0000 Subject: [PATCH 03/19] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a5763fe5c5..b7ba70b62f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1439,6 +1439,7 @@ "Add User": "Add User", "All rooms": "All rooms", "Your server": "Your server", + "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", From 343403f1efcdf8b4150d903e0a4d21e49b59d23d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:09:56 +0000 Subject: [PATCH 04/19] clean up Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 3dc3a99dd4..f3c2f4757a 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -1,5 +1,4 @@ /* -Copyright 2015, 2016 OpenMarket Ltd Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,11 +29,6 @@ limitations under the License. } .mx_NetworkDropdown_menu { - //position: absolute; - //left: -1px; - //right: -1px; - //top: 100%; - //z-index: 2; width: 204px; margin: 0; box-sizing: border-box; From 359b07b8efc667945d3f3476fbd9658dd1f8b21c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:11:09 +0000 Subject: [PATCH 05/19] allow it to expand for longer content Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index f3c2f4757a..1f55531602 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -29,7 +29,7 @@ limitations under the License. } .mx_NetworkDropdown_menu { - width: 204px; + min-width: 204px; margin: 0; box-sizing: border-box; border-radius: 4px; From 642dd08ca25065237d157e5759efae77d94fe315 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:16:11 +0000 Subject: [PATCH 06/19] remove erroneous margin Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index d6ae0bb739..b5ead78b8b 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -48,7 +48,6 @@ limitations under the License. .mx_RoomDirectory_listheader { display: block; margin-top: 13px; - margin-bottom: 13px; } .mx_RoomDirectory_searchbox { From 3628fd2ea26b12ee25d96ef453acd47edca3bc34 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:18:33 +0000 Subject: [PATCH 07/19] add missing asset Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/img/feather-customised/chevron-down.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 res/img/feather-customised/chevron-down.svg diff --git a/res/img/feather-customised/chevron-down.svg b/res/img/feather-customised/chevron-down.svg new file mode 100644 index 0000000000..bcb185ede7 --- /dev/null +++ b/res/img/feather-customised/chevron-down.svg @@ -0,0 +1,3 @@ + + + From 5a27fa7d97eb6f85171730179cba4cdd3dc9b34f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:18:53 +0000 Subject: [PATCH 08/19] fix styling of server name in handle Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 5 +++++ src/components/views/directory/NetworkDropdown.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 1f55531602..f017ed9dcd 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -149,4 +149,9 @@ limitations under the License. mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); background-color: $primary-fg-color; } + + .mx_NetworkDropdown_handle_server { + color: $muted-fg-color; + font-size: 12px; + } } diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 229f80ef29..8369926fb4 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -223,7 +223,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se > {currentValue} - + ({selectedServerName}) ; From 9237cf956640f73d79ddb884b127b8cb46f2ad33 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:19:38 +0000 Subject: [PATCH 09/19] update font sizes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 5 +++-- res/css/views/directory/_NetworkDropdown.scss | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index b5ead78b8b..f3a7b0e243 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -64,7 +64,7 @@ limitations under the License. } .mx_RoomDirectory_table { - font-size: 14px; + font-size: 12px; color: $primary-fg-color; width: 100%; text-align: left; @@ -112,6 +112,7 @@ limitations under the License. .mx_RoomDirectory_name { display: inline-block; + font-size: 18px; font-weight: 600; } @@ -149,7 +150,7 @@ limitations under the License. } .mx_RoomDirectory > span { - font-size: 14px; + font-size: 15px; margin-top: 0; .mx_AccessibleButton { diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index f017ed9dcd..7e8a2e16d1 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -58,7 +58,7 @@ limitations under the License. display: inline; right: 0; - &::before { + &::after { content: ""; position: absolute; width: 16px; From af368a4736f546aec0ff24e29ead2aa16bf9b692 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:38:36 +0000 Subject: [PATCH 10/19] Improve accessibility Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 5 +++-- src/components/structures/ContextMenu.js | 3 +-- .../views/directory/NetworkDropdown.js | 20 +++++++++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 7e8a2e16d1..28dd1ed628 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -56,14 +56,15 @@ limitations under the License. .mx_AccessibleButton { position: absolute; display: inline; - right: 0; + right: 12px; + height: 16px; + width: 16px; &::after { content: ""; position: absolute; width: 16px; height: 16px; - right: 12px; top: 4px; mask-repeat: no-repeat; mask-position: center; diff --git a/src/components/structures/ContextMenu.js b/src/components/structures/ContextMenu.js index 898991f4f2..b4647a6c30 100644 --- a/src/components/structures/ContextMenu.js +++ b/src/components/structures/ContextMenu.js @@ -350,7 +350,7 @@ export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => }; ContextMenuButton.propTypes = { ...AccessibleButton.propTypes, - label: PropTypes.string.isRequired, + label: PropTypes.string, isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open }; @@ -377,7 +377,6 @@ export const MenuGroup = ({children, label, ...props}) => { ; }; MenuGroup.propTypes = { - ...AccessibleButton.propTypes, label: PropTypes.string.isRequired, className: PropTypes.string, // optional }; diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 8369926fb4..637fb09c18 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -21,7 +21,14 @@ import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; -import {ContextMenu, useContextMenu, ContextMenuButton, MenuItemRadio, MenuItem} from "../../structures/ContextMenu"; +import { + ContextMenu, + useContextMenu, + ContextMenuButton, + MenuItemRadio, + MenuItem, + MenuGroup +} from "../../structures/ContextMenu"; import {_t} from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import {useSettingValue} from "../../../hooks/useSettings"; @@ -147,11 +154,13 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se onOptionChange(hsName, undefined); } }; - removeButton = ; + removeButton = ; } + // ARIA: in actual fact the entire menu is one large radio group but for better screen reader support + // we use group to notate server wrongly. return ( -
+
{ server } { removeButton } @@ -167,7 +176,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se {_t("Matrix")} { entries } -
+
); }); @@ -194,7 +203,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se }; const buttonRect = handle.current.getBoundingClientRect(); - content = + content =
{options} @@ -217,7 +226,6 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se content = From 401d85ea6fd156bd2f2f46ce7a86db694a4deeaf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:42:19 +0000 Subject: [PATCH 11/19] delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 3 +-- src/i18n/strings/en_EN.json | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 637fb09c18..22f919b162 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -27,7 +27,7 @@ import { ContextMenuButton, MenuItemRadio, MenuItem, - MenuGroup + MenuGroup, } from "../../structures/ContextMenu"; import {_t} from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; @@ -35,7 +35,6 @@ import {useSettingValue} from "../../../hooks/useSettings"; import * as sdk from "../../../index"; import Modal from "../../../Modal"; import SettingsStore from "../../../settings/SettingsStore"; -import AccessibleButton from "../elements/AccessibleButton"; export const ALL_ROOMS = Symbol("ALL_ROOMS"); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b7ba70b62f..59bc643539 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1440,6 +1440,7 @@ "All rooms": "All rooms", "Your server": "Your server", "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", + "Remove server": "Remove server", "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", From 84332184b518b9609cda77e7becb75d4761d0bb7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:50:41 +0000 Subject: [PATCH 12/19] no need to await here as settings take a while to effect, we watch them elsewhere Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- src/components/views/directory/NetworkDropdown.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 28dd1ed628..61f9825143 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -59,13 +59,13 @@ limitations under the License. right: 12px; height: 16px; width: 16px; + margin-top: 4px; &::after { content: ""; position: absolute; width: 16px; height: 16px; - top: 4px; mask-repeat: no-repeat; mask-position: center; mask-size: contain; diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 22f919b162..c4a70c112e 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -146,7 +146,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; // delete from setting - await SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); + SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); // the selected server is being removed, reset to our HS if (serverSelected === server) { @@ -195,7 +195,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!userDefinedServers.includes(newServer)) { const servers = [...userDefinedServers, newServer]; - await SettingsStore.setValue(SETTING_NAME, null, "account", servers); + SettingsStore.setValue(SETTING_NAME, null, "account", servers); } onOptionChange(newServer); // change filter to the new server From 4de0e21a4b596a0ef6083c00afd860c407a14dda Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 15:28:22 +0000 Subject: [PATCH 13/19] fix styling mistakes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 61f9825143..b23af0b2a0 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -33,7 +33,7 @@ limitations under the License. margin: 0; box-sizing: border-box; border-radius: 4px; - border: 1px solid $accent-color; + border: 1px solid $dialog-close-fg-color; background-color: $primary-bg-color; } @@ -120,6 +120,7 @@ limitations under the License. .mx_NetworkDropdown_server_add { padding: 16px 10px 16px 32px; position: relative; + border-radius: 0 0 4px 4px; &::before { content: ""; From ee1659625cfa7affa8ec873279cca35d3b5cd518 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 17:32:02 +0000 Subject: [PATCH 14/19] Add Field validation to TextInputDialog Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/TextInputDialog.js | 59 +++++++++++++++---- .../views/directory/NetworkDropdown.js | 30 ++++++++++ src/i18n/strings/en_EN.json | 3 + 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 4b21e8206e..e56e9f2b87 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -18,6 +18,7 @@ import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import Field from "../elements/Field"; export default createReactClass({ displayName: 'TextInputDialog', @@ -33,6 +34,7 @@ export default createReactClass({ focus: PropTypes.bool, onFinished: PropTypes.func.isRequired, hasCancel: PropTypes.bool, + validator: PropTypes.func, // result of withValidation }, getDefaultProps: function() { @@ -45,25 +47,57 @@ export default createReactClass({ }; }, + getInitialState: function() { + return { + value: this.props.value, + valid: false, + }; + }, + UNSAFE_componentWillMount: function() { - this._textinput = createRef(); + this._field = createRef(); }, componentDidMount: function() { if (this.props.focus) { // Set the cursor at the end of the text input - this._textinput.current.value = this.props.value; + // this._field.current.value = this.props.value; + this._field.current.focus(); } }, - onOk: function() { - this.props.onFinished(true, this._textinput.current.value); + onOk: async function(ev) { + ev.preventDefault(); + if (this.props.validator) { + await this._field.current.validate({ allowEmpty: false }); + + if (!this._field.current.state.valid) { + this._field.current.focus(); + this._field.current.validate({ allowEmpty: false, focused: true }); + return; + } + } + this.props.onFinished(true, this.state.value); }, onCancel: function() { this.props.onFinished(false); }, + onChange: function(ev) { + this.setState({ + value: ev.target.value, + }); + }, + + onValidate: async function(fieldState) { + const result = await this.props.validator(fieldState); + this.setState({ + valid: result.valid, + }); + return result; + }, + render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -77,14 +111,17 @@ export default createReactClass({
- + ref={this._field} + type="text" + label={this.props.placeholder} + value={this.state.value} + onChange={this.onChange} + onValidate={this.props.validator ? this.onValidate : undefined} + size="64" + />
diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index c4a70c112e..6d1501ca57 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -35,6 +35,7 @@ import {useSettingValue} from "../../../hooks/useSettings"; import * as sdk from "../../../index"; import Modal from "../../../Modal"; import SettingsStore from "../../../settings/SettingsStore"; +import withValidation from "../elements/Validation"; export const ALL_ROOMS = Symbol("ALL_ROOMS"); @@ -47,6 +48,34 @@ const inPlaceOf = (elementRect) => ({ chevronFace: "none", }); +const validServer = withValidation({ + rules: [ + { + key: "required", + test: async ({ value }) => !!value, + invalid: () => _t("Enter a server address"), + }, { + key: "available", + final: true, + test: async ({ value }) => { + try { + const opts = { + limit: 1, + server: value, + }; + // check if we can successfully load this server's room directory + await MatrixClientPeg.get().publicRooms(opts); + return true; + } catch (e) { + return false; + } + }, + valid: () => _t("Looks good"), + invalid: () => _t("Can't find this server or its room list"), + }, + ], +}); + // This dropdown sources homeservers from three places: // + your currently connected homeserver // + homeservers in config.json["roomDirectory"] @@ -188,6 +217,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se button: _t("Add"), hasCancel: false, placeholder: _t("Server address"), + validator: validServer, }); const [ok, newServer] = await finished; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 59bc643539..3f20d4ec61 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,6 +1437,9 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "Enter a server address": "Enter a server address", + "Looks good": "Looks good", + "Can't find this server or its room list": "Can't find this server or its room list", "All rooms": "All rooms", "Your server": "Your server", "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", From 6f27c4c17af4e47272ff21815c57b35da9d23456 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 11:45:51 +0000 Subject: [PATCH 15/19] s/Server address/Server name/ Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 4 ++-- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 6d1501ca57..e56cfcf185 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -53,7 +53,7 @@ const validServer = withValidation({ { key: "required", test: async ({ value }) => !!value, - invalid: () => _t("Enter a server address"), + invalid: () => _t("Enter a server name"), }, { key: "available", final: true, @@ -216,7 +216,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se description: _t("Enter the address of a new server you want to explore."), button: _t("Add"), hasCancel: false, - placeholder: _t("Server address"), + placeholder: _t("Server name"), validator: validServer, }); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3f20d4ec61..e990f76519 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,7 +1437,7 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", - "Enter a server address": "Enter a server address", + "Enter a server name": "Enter a server name", "Looks good": "Looks good", "Can't find this server or its room list": "Can't find this server or its room list", "All rooms": "All rooms", @@ -1447,7 +1447,7 @@ "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", - "Server address": "Server address", + "Server name": "Server name", "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", From 82a37ba0ad429c09c101e175dd0650773dd67a2d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:00:56 +0000 Subject: [PATCH 16/19] Fix styling of NetworkDropdown dialogs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 4 ++++ src/components/views/dialogs/QuestionDialog.js | 6 +++++- src/components/views/dialogs/TextInputDialog.js | 6 +++++- src/components/views/directory/NetworkDropdown.js | 6 ++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index b23af0b2a0..e60c481e45 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -157,3 +157,7 @@ limitations under the License. font-size: 12px; } } + +.mx_NetworkDropdown_dialog .mx_Dialog { + width: 557px; +} diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index 8cb16dd88f..07a1eae5d5 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -33,6 +33,7 @@ export default createReactClass({ onFinished: PropTypes.func.isRequired, headerImage: PropTypes.string, quitOnly: PropTypes.bool, // quitOnly doesn't show the cancel button just the quit [x]. + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -63,11 +64,14 @@ export default createReactClass({ primaryButtonClass = "danger"; } return ( -
{ this.props.description } diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index e56e9f2b87..b9f6f6ebce 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -35,6 +35,7 @@ export default createReactClass({ onFinished: PropTypes.func.isRequired, hasCancel: PropTypes.bool, validator: PropTypes.func, // result of withValidation + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -102,8 +103,11 @@ export default createReactClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( -
diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index e56cfcf185..85d72e33f0 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -169,7 +169,8 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se b: serverName => { serverName }, }), button: _t("Remove"), - }); + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); const [ok] = await finished; if (!ok) return; @@ -218,7 +219,8 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se hasCancel: false, placeholder: _t("Server name"), validator: validServer, - }); + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); const [ok, newServer] = await finished; if (!ok) return; From 454b32400dbc9d190dc594ebf3115bfe9e8cb277 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:12:59 +0000 Subject: [PATCH 17/19] improve width Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index e60c481e45..106392f880 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -159,5 +159,5 @@ limitations under the License. } .mx_NetworkDropdown_dialog .mx_Dialog { - width: 557px; + width: 45vw; } From eabaf5801388e40cba45322335be01d765472cbb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:20:52 +0000 Subject: [PATCH 18/19] Add local-echo Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/directory/NetworkDropdown.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 85d72e33f0..425b951929 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {useEffect, useState} from 'react'; import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; @@ -84,7 +84,8 @@ const validServer = withValidation({ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, selectedInstanceId}) => { const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); - const userDefinedServers = useSettingValue(SETTING_NAME); + const _userDefinedServers = useSettingValue(SETTING_NAME); + const [userDefinedServers, _setUserDefinedServers] = useState(_userDefinedServers); const handlerFactory = (server, instanceId) => { return () => { @@ -93,6 +94,15 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se }; }; + const setUserDefinedServers = servers => { + _setUserDefinedServers(servers); + SettingsStore.setValue(SETTING_NAME, null, "account", servers); + }; + // keep local echo up to date with external changes + useEffect(() => { + _setUserDefinedServers(_userDefinedServers); + }, [_userDefinedServers]); + // we either show the button or the dropdown in its place. let content; if (menuDisplayed) { @@ -176,7 +186,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; // delete from setting - SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); + setUserDefinedServers(servers.filter(s => s !== server)); // the selected server is being removed, reset to our HS if (serverSelected === server) { @@ -226,8 +236,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; if (!userDefinedServers.includes(newServer)) { - const servers = [...userDefinedServers, newServer]; - SettingsStore.setValue(SETTING_NAME, null, "account", servers); + setUserDefinedServers([...userDefinedServers, newServer]); } onOptionChange(newServer); // change filter to the new server From 78543da7f4bb989499bbfac56d7ec27d21164177 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:28:20 +0000 Subject: [PATCH 19/19] Fix missed copy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 425b951929..2fabda1a74 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -224,7 +224,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, { title: _t("Add a new server"), - description: _t("Enter the address of a new server you want to explore."), + description: _t("Enter the name of a new server you want to explore."), button: _t("Add"), hasCancel: false, placeholder: _t("Server name"), diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e990f76519..a14e275a51 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1446,7 +1446,7 @@ "Remove server": "Remove server", "Matrix": "Matrix", "Add a new server": "Add a new server", - "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", + "Enter the name of a new server you want to explore.": "Enter the name of a new server you want to explore.", "Server name": "Server name", "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms",