;
- },
-});
+ );
+ }
-// TODO: Make this use the new Field element
-module.exports = React.createClass({
- displayName: 'EditableItemList',
+ return (
+
- { editableItems }
- { this.props.canEdit ?
- // This is slightly evil; we want a new instance of
- // EditableItem when the list grows. To make sure it's
- // reset to its initial state.
- :
- }
+ { editableItemsSection }
+ { this.props.canEdit ? this._renderNewItemField() : }
);
- },
-});
+ }
+}
diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js
index 827656e770..df427171f1 100644
--- a/src/components/views/room_settings/AliasSettings.js
+++ b/src/components/views/room_settings/AliasSettings.js
@@ -1,6 +1,6 @@
/*
Copyright 2016 OpenMarket Ltd
-Copyright 2018 New Vector Ltd
+Copyright 2018, 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,112 +15,55 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import Promise from 'bluebird';
const React = require('react');
import PropTypes from 'prop-types';
-const ObjectUtils = require("../../../ObjectUtils");
const MatrixClientPeg = require('../../../MatrixClientPeg');
const sdk = require("../../../index");
import { _t } from '../../../languageHandler';
import Field from "../elements/Field";
+import ErrorDialog from "../dialogs/ErrorDialog";
const Modal = require("../../../Modal");
-module.exports = React.createClass({
- displayName: 'AliasSettings',
-
- propTypes: {
+export default class AliasSettings extends React.Component {
+ static propTypes = {
roomId: PropTypes.string.isRequired,
canSetCanonicalAlias: PropTypes.bool.isRequired,
canSetAliases: PropTypes.bool.isRequired,
aliasEvents: PropTypes.array, // [MatrixEvent]
canonicalAliasEvent: PropTypes.object, // MatrixEvent
- },
+ };
- getDefaultProps: function() {
- return {
- canSetAliases: false,
- canSetCanonicalAlias: false,
- aliasEvents: [],
- };
- },
+ static defaultProps = {
+ canSetAliases: false,
+ canSetCanonicalAlias: false,
+ aliasEvents: [],
+ };
- getInitialState: function() {
- return this.recalculateState(this.props.aliasEvents, this.props.canonicalAliasEvent);
- },
-
- recalculateState: function(aliasEvents, canonicalAliasEvent) {
- aliasEvents = aliasEvents || [];
+ constructor(props) {
+ super(props);
const state = {
domainToAliases: {}, // { domain.com => [#alias1:domain.com, #alias2:domain.com] }
remoteDomains: [], // [ domain.com, foobar.com ]
canonicalAlias: null, // #canonical:domain.com
+ updatingCanonicalAlias: false,
+ newItem: "",
};
+
const localDomain = MatrixClientPeg.get().getDomain();
-
- state.domainToAliases = this.aliasEventsToDictionary(aliasEvents);
-
+ state.domainToAliases = this.aliasEventsToDictionary(props.aliasEvents || []);
state.remoteDomains = Object.keys(state.domainToAliases).filter((domain) => {
return domain !== localDomain && state.domainToAliases[domain].length > 0;
});
- if (canonicalAliasEvent) {
- state.canonicalAlias = canonicalAliasEvent.getContent().alias;
+ if (props.canonicalAliasEvent) {
+ state.canonicalAlias = props.canonicalAliasEvent.getContent().alias;
}
- return state;
- },
+ this.state = state;
+ }
- saveSettings: function() {
- let promises = [];
-
- // save new aliases for m.room.aliases
- const aliasOperations = this.getAliasOperations();
- for (let i = 0; i < aliasOperations.length; i++) {
- const alias_operation = aliasOperations[i];
- console.log("alias %s %s", alias_operation.place, alias_operation.val);
- switch (alias_operation.place) {
- case 'add':
- promises.push(
- MatrixClientPeg.get().createAlias(
- alias_operation.val, this.props.roomId,
- ),
- );
- break;
- case 'del':
- promises.push(
- MatrixClientPeg.get().deleteAlias(
- alias_operation.val,
- ),
- );
- break;
- default:
- console.log("Unknown alias operation, ignoring: " + alias_operation.place);
- }
- }
-
- let oldCanonicalAlias = null;
- if (this.props.canonicalAliasEvent) {
- oldCanonicalAlias = this.props.canonicalAliasEvent.getContent().alias;
- }
-
- const newCanonicalAlias = this.state.canonicalAlias;
-
- if (this.props.canSetCanonicalAlias && oldCanonicalAlias !== newCanonicalAlias) {
- console.log("AliasSettings: Updating canonical alias");
- promises = [Promise.all(promises).then(
- MatrixClientPeg.get().sendStateEvent(
- this.props.roomId, "m.room.canonical_alias", {
- alias: newCanonicalAlias,
- }, "",
- ),
- )];
- }
-
- return promises;
- },
-
- aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events
+ aliasEventsToDictionary(aliasEvents) { // m.room.alias events
const dict = {};
aliasEvents.forEach((event) => {
dict[event.getStateKey()] = (
@@ -128,35 +71,72 @@ module.exports = React.createClass({
);
});
return dict;
- },
+ }
- isAliasValid: function(alias) {
+ isAliasValid(alias) {
// XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
- return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
- },
+ return (alias.match(/^#([^/:,]+?):(.+)$/) && encodeURI(alias) === alias);
+ }
- getAliasOperations: function() {
- const oldAliases = this.aliasEventsToDictionary(this.props.aliasEvents);
- return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
- },
+ changeCanonicalAlias(alias) {
+ if (!this.props.canSetCanonicalAlias) return;
- onNewAliasChanged: function(value) {
+ this.setState({
+ canonicalAlias: alias,
+ updatingCanonicalAlias: true,
+ });
+
+ const eventContent = {};
+ if (alias) eventContent["alias"] = alias;
+
+ MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.canonical_alias",
+ eventContent, "").catch((err) => {
+ console.error(err);
+ Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
+ title: _t("Error updating main address"),
+ description: _t(
+ "There was an error updating the room's main address. It may not be allowed by the server " +
+ "or a temporary failure occurred.",
+ ),
+ });
+ }).finally(() => {
+ this.setState({updatingCanonicalAlias: false});
+ });
+ }
+
+ onNewAliasChanged = (value) => {
this.setState({newAlias: value});
- },
+ };
- onLocalAliasAdded: function(alias) {
+ onLocalAliasAdded = (alias) => {
if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases
const localDomain = MatrixClientPeg.get().getDomain();
if (!alias.includes(':')) alias += ':' + localDomain;
if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
- this.state.domainToAliases[localDomain] = this.state.domainToAliases[localDomain] || [];
- this.state.domainToAliases[localDomain].push(alias);
+ MatrixClientPeg.get().createAlias(alias, this.props.roomId).then(() => {
+ const localAliases = this.state.domainToAliases[localDomain] || [];
+ const domainAliases = Object.assign({}, this.state.domainToAliases);
+ domainAliases[localDomain] = [...localAliases, alias];
- this.setState({
- domainToAliases: this.state.domainToAliases,
- // Reset the add field
- newAlias: "",
+ this.setState({
+ domainToAliases: domainAliases,
+ // Reset the add field
+ newAlias: "",
+ });
+
+ if (!this.state.canonicalAlias) {
+ this.changeCanonicalAlias(alias);
+ }
+ }).catch((err) => {
+ console.error(err);
+ Modal.createTrackedDialog('Error creating alias', '', ErrorDialog, {
+ title: _t("Error creating alias"),
+ description: _t(
+ "There was an error creating that alias. It may not be allowed by the server " +
+ "or a temporary failure occurred.",
+ ),
+ });
});
} else {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@@ -165,130 +145,102 @@ module.exports = React.createClass({
description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
});
}
+ };
- if (!this.props.canonicalAlias) {
- this.setState({
- canonicalAlias: alias,
- });
- }
- },
-
- onLocalAliasChanged: function(alias, index) {
- if (alias === "") return; // hit the delete button to delete please
+ onLocalAliasDeleted = (index) => {
const localDomain = MatrixClientPeg.get().getDomain();
- if (!alias.includes(':')) alias += ':' + localDomain;
- if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
- this.state.domainToAliases[localDomain][index] = alias;
- } else {
- const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
- Modal.createTrackedDialog('Invalid address format', '', ErrorDialog, {
- title: _t('Invalid address format'),
- description: _t('\'%(alias)s\' is not a valid format for an address', { alias: alias }),
+
+ const alias = this.state.domainToAliases[localDomain][index];
+
+ // TODO: In future, we should probably be making sure that the alias actually belongs
+ // to this room. See https://github.com/vector-im/riot-web/issues/7353
+ MatrixClientPeg.get().deleteAlias(alias).then(() => {
+ const localAliases = this.state.domainToAliases[localDomain].filter((a) => a !== alias);
+ const domainAliases = Object.assign({}, this.state.domainToAliases);
+ domainAliases[localDomain] = localAliases;
+
+ this.setState({domainToAliases: domainAliases});
+
+ if (this.state.canonicalAlias === alias) {
+ this.changeCanonicalAlias(null);
+ }
+ }).catch((err) => {
+ console.error(err);
+ Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, {
+ title: _t("Error removing alias"),
+ description: _t(
+ "There was an error removing that alias. It may no longer exist or a temporary " +
+ "error occurred.",
+ ),
});
- }
- },
-
- onLocalAliasDeleted: function(index) {
- const localDomain = MatrixClientPeg.get().getDomain();
- // It's a bit naughty to directly manipulate this.state, and React would
- // normally whine at you, but it can't see us doing the splice. Given we
- // promptly setState anyway, it's just about acceptable. The alternative
- // would be to arbitrarily deepcopy to a temp variable and then setState
- // that, but why bother when we can cut this corner.
- const alias = this.state.domainToAliases[localDomain].splice(index, 1);
- this.setState({
- domainToAliases: this.state.domainToAliases,
});
- if (this.props.canonicalAlias === alias) {
- this.setState({
- canonicalAlias: null,
- });
- }
- },
+ };
- onCanonicalAliasChange: function(event) {
- this.setState({
- canonicalAlias: event.target.value,
- });
- },
+ onCanonicalAliasChange = (event) => {
+ this.changeCanonicalAlias(event.target.value);
+ };
- render: function() {
- const self = this;
- const EditableText = sdk.getComponent("elements.EditableText");
+ render() {
const EditableItemList = sdk.getComponent("elements.EditableItemList");
const localDomain = MatrixClientPeg.get().getDomain();
- let canonical_alias_section;
- if (this.props.canSetCanonicalAlias) {
- let found = false;
- const canonicalValue = this.state.canonicalAlias || "";
- canonical_alias_section = (
-
-
- {
- Object.keys(self.state.domainToAliases).map((domain, i) => {
- return self.state.domainToAliases[domain].map((alias, j) => {
- if (alias === this.state.canonicalAlias) found = true;
- return (
-
- );
- });
- })
- }
- {
- found || !this.stateCanonicalAlias ? '' :
-
- }
-
- );
- } else {
- canonical_alias_section = (
- { this.state.canonicalAlias || _t('not set') }
- );
- }
+ let found = false;
+ const canonicalValue = this.state.canonicalAlias || "";
+ const canonicalAliasSection = (
+
+
+ {
+ Object.keys(this.state.domainToAliases).map((domain, i) => {
+ return this.state.domainToAliases[domain].map((alias, j) => {
+ if (alias === this.state.canonicalAlias) found = true;
+ return (
+
+ );
+ });
+ })
+ }
+ {
+ found || !this.state.canonicalAlias ? '' :
+
+ }
+
+ );
- let remote_aliases_section;
+ let remoteAliasesSection;
if (this.state.remoteDomains.length) {
- remote_aliases_section = (
+ remoteAliasesSection = (
{_t("URL Previews")}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 63369ce991..84c9dacd07 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -192,6 +192,9 @@
"%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s has allowed guests to join the room.",
"%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s has prevented guests from joining the room.",
"%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s changed guest access to %(rule)s",
+ "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s enabled flair for %(groups)s in this room.",
+ "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s disabled flair for %(groups)s in this room.",
+ "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.",
"%(senderDisplayName)s sent an image.": "%(senderDisplayName)s sent an image.",
"%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s added %(addedAddresses)s as addresses for this room.",
"%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s added %(addedAddresses)s as an address for this room.",
@@ -804,17 +807,22 @@
"Hide Stickers": "Hide Stickers",
"Show Stickers": "Show Stickers",
"Jump to first unread message.": "Jump to first unread message.",
+ "Error updating main address": "Error updating main address",
+ "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.",
+ "Error creating alias": "Error creating alias",
+ "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.",
"Invalid alias format": "Invalid alias format",
"'%(alias)s' is not a valid format for an alias": "'%(alias)s' is not a valid format for an alias",
- "Invalid address format": "Invalid address format",
- "'%(alias)s' is not a valid format for an address": "'%(alias)s' is not a valid format for an address",
+ "Error removing alias": "Error removing alias",
+ "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "There was an error removing that alias. It may no longer exist or a temporary error occurred.",
"Main address": "Main address",
"not specified": "not specified",
- "not set": "not set",
"Remote addresses for this room:": "Remote addresses for this room:",
"Local addresses for this room:": "Local addresses for this room:",
"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)",
+ "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.",
"Invalid community ID": "Invalid community ID",
"'%(groupId)s' is not a valid community ID": "'%(groupId)s' is not a valid community ID",
"Showing flair for these communities:": "Showing flair for these communities:",
@@ -925,7 +933,6 @@
"Verify...": "Verify...",
"Join": "Join",
"No results": "No results",
- "Delete": "Delete",
"Communities": "Communities",
"Home": "Home",
"You cannot delete this image. (%(code)s)": "You cannot delete this image. (%(code)s)",