diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml
deleted file mode 100644
index 4bc69a76bd..0000000000
--- a/.buildkite/pipeline.yaml
+++ /dev/null
@@ -1,119 +0,0 @@
-steps:
- - label: ":eslint: JS Lint"
- command:
- # We fetch the develop js-sdk to get our latest eslint rules
- - "echo '--- Install js-sdk'"
- - "./scripts/ci/install-deps.sh --ignore-scripts"
- - "echo '+++ Lint'"
- - "yarn lint:js"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
-
- - label: ":eslint: TS Lint"
- command:
- - "echo '--- Install'"
- - "yarn install --ignore-scripts"
- - "echo '+++ Lint'"
- - "yarn lint:ts"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
-
- - label: ":eslint: Types Lint"
- command:
- - "echo '--- Install'"
- - "yarn install --ignore-scripts"
- - "echo '+++ Lint'"
- - "yarn lint:types"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
- - label: ":stylelint: Style Lint"
- command:
- - "echo '--- Install'"
- - "yarn install --ignore-scripts"
- - "yarn lint:style"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
-
- - label: ":jest: Tests"
- agents:
- # We use a medium sized instance instead of the normal small ones because
- # webpack loves to gorge itself on resources.
- queue: "medium"
- command:
- - "echo '--- Install js-sdk'"
- # We don't use the babel-ed output for anything so we can --ignore-scripts
- # to save transpiling the files. We run the transpile step explicitly in
- # the 'build' job.
- - "./scripts/ci/install-deps.sh --ignore-scripts"
- - "yarn run reskindex"
- - "echo '+++ Running Tests'"
- - "yarn test"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
-
- - label: "🛠 Build"
- command:
- - "echo '+++ Install & Build'"
- - "yarn install"
- plugins:
- - docker#v3.0.1:
- image: "node:12"
-
- - label: ":chains: End-to-End Tests"
- agents:
- # We use a xlarge sized instance instead of the normal small ones because
- # e2e tests otherwise take +-8min
- queue: "xlarge"
- command:
- - "echo '--- Install js-sdk'"
- - "./scripts/ci/install-deps.sh --ignore-scripts"
- - "echo '+++ Running Tests'"
- - "./scripts/ci/end-to-end-tests.sh"
- plugins:
- - docker#v3.0.1:
- image: "matrixdotorg/riotweb-ci-e2etests-env:latest"
- propagate-environment: true
- workdir: "/workdir/matrix-react-sdk"
- retry:
- automatic:
- - exit_status: 1 # retry end-to-end tests once as Puppeteer sometimes fails
- limit: 1
-
- - label: "🔧 Riot Tests"
- agents:
- # We use a medium sized instance instead of the normal small ones because
- # webpack loves to gorge itself on resources.
- queue: "medium"
- command:
- - "echo '+++ Running Tests'"
- - "./scripts/ci/riot-unit-tests.sh"
- plugins:
- - docker#v3.0.1:
- image: "node:10"
- propagate-environment: true
- workdir: "/workdir/matrix-react-sdk"
-
- - label: "🌐 i18n"
- command:
- - "echo '--- Fetching Dependencies'"
- - "yarn install --ignore-scripts"
- - "echo '+++ Testing i18n output'"
- - "yarn diff-i18n"
- plugins:
- - docker#v3.0.1:
- image: "node:10"
-
- - wait
-
- - label: "🐴 Trigger riot-web"
- trigger: "riot-web"
- branches: "develop"
- build:
- branch: "develop"
- message: "[react-sdk] ${BUILDKITE_MESSAGE}"
- async: true
diff --git a/.eslintignore b/.eslintignore
index c4c7fe5067..c4f7298047 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1 +1,4 @@
src/component-index.js
+test/end-to-end-tests/node_modules/
+test/end-to-end-tests/riot/
+test/end-to-end-tests/synapse/
diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles
index 36b03b121c..ffd398cb14 100644
--- a/.eslintignore.errorfiles
+++ b/.eslintignore.errorfiles
@@ -61,3 +61,7 @@ test/mock-clock.js
test/notifications/ContentRules-test.js
test/notifications/PushRuleVectorState-test.js
test/stores/RoomViewStore-test.js
+src/component-index.js
+test/end-to-end-tests/node_modules/
+test/end-to-end-tests/riot/
+test/end-to-end-tests/synapse/
diff --git a/package.json b/package.json
index 09393f052a..624f2d6ecb 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"pako": "^1.0.5",
"png-chunks-extract": "^1.0.0",
"prop-types": "^15.5.8",
+ "qrcode": "^1.4.4",
"qrcode-react": "^0.1.16",
"qs": "^6.6.0",
"react": "^16.9.0",
diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss
index 9d58c999c3..500c46b5fd 100644
--- a/res/css/views/dialogs/_DevtoolsDialog.scss
+++ b/res/css/views/dialogs/_DevtoolsDialog.scss
@@ -189,3 +189,37 @@ limitations under the License.
}
}
}
+
+.mx_DevTools_VerificationRequest {
+ border: 1px solid #cccccc;
+ border-radius: 3px;
+ padding: 1px 5px;
+ margin-bottom: 6px;
+ font-family: $monospace-font-family;
+
+ dl {
+ display: grid;
+ grid-template-columns: max-content auto;
+ margin: 0;
+ }
+
+ dd {
+ grid-column-start: 2;
+ }
+
+ dd:empty {
+ color: #666666;
+ &::after {
+ content: "(empty)";
+ }
+ }
+
+ dt {
+ font-weight: bold;
+ grid-column-start: 1;
+ }
+
+ dt::after {
+ content: ":";
+ }
+}
diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss
index 46d5e99d64..0e4b1bda9e 100644
--- a/res/css/views/right_panel/_UserInfo.scss
+++ b/res/css/views/right_panel/_UserInfo.scss
@@ -137,12 +137,19 @@ limitations under the License.
font-size: 18px;
line-height: 25px;
flex: 1;
- overflow-x: auto;
- max-height: 50px;
- display: flex;
justify-content: center;
align-items: center;
+ // limit to 2 lines, show an ellipsis if it overflows
+ // this looks webkit specific but is supported by Firefox 68+
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+
+ overflow: hidden;
+ word-break: break-all;
+ text-overflow: ellipsis;
+
.mx_E2EIcon {
margin: 5px;
}
diff --git a/res/css/views/rooms/_InviteOnlyIcon.scss b/res/css/views/rooms/_InviteOnlyIcon.scss
index 6943d1797b..b71fd6348d 100644
--- a/res/css/views/rooms/_InviteOnlyIcon.scss
+++ b/res/css/views/rooms/_InviteOnlyIcon.scss
@@ -14,27 +14,45 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_InviteOnlyIcon {
+@define-mixin mx_InviteOnlyIcon {
width: 12px;
height: 12px;
position: relative;
display: block !important;
- // Align the padlock with unencrypted room names
+}
+
+@define-mixin mx_InviteOnlyIcon_padlock {
+ background-color: $roomtile-name-color;
+ mask-image: url("$(res)/img/feather-customised/lock-solid.svg");
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+
+.mx_InviteOnlyIcon_large {
+ @mixin mx_InviteOnlyIcon;
margin: 0 4px;
&::before {
- background-color: $roomtile-name-color;
- mask-image: url('$(res)/img/feather-customised/lock-solid.svg');
- mask-position: center;
- mask-repeat: no-repeat;
- mask-size: contain;
- content: '';
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
+ @mixin mx_InviteOnlyIcon_padlock;
width: 12px;
height: 12px;
}
}
+
+.mx_InviteOnlyIcon_small {
+ @mixin mx_InviteOnlyIcon;
+ left: -2px;
+
+ &::before {
+ @mixin mx_InviteOnlyIcon_padlock;
+ width: 10px;
+ height: 10px;
+ }
+}
diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss
index c868c81549..626ccb2e13 100644
--- a/res/themes/light/css/_light.scss
+++ b/res/themes/light/css/_light.scss
@@ -5,9 +5,12 @@
Arial empirically gets it right, hence prioritising Arial here. */
/* We fall through to Twemoji for emoji rather than falling through
to native Emoji fonts (if any) to ensure cross-browser consistency */
-$font-family: Nunito, Twemoji, 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', Arial, Helvetica, Sans-Serif;
+/* Noto Color Emoji contains digits, in fixed-width, therefore causing
+ digits in flowed text to stand out.
+ TODO: Consider putting all emoji fonts to the end rather than the front. */
+$font-family: Nunito, Twemoji, 'Apple Color Emoji', 'Segoe UI Emoji', Arial, Helvetica, Sans-Serif, 'Noto Color Emoji';
-$monospace-font-family: Inconsolata, Twemoji, 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', Courier, monospace;
+$monospace-font-family: Inconsolata, Twemoji, 'Apple Color Emoji', 'Segoe UI Emoji', Courier, monospace, 'Noto Color Emoji';
// unified palette
// try to use these colors when possible
diff --git a/scripts/generate-eslint-error-ignore-file b/scripts/generate-eslint-error-ignore-file
index 3a635f5a7d..54aacfc9fa 100755
--- a/scripts/generate-eslint-error-ignore-file
+++ b/scripts/generate-eslint-error-ignore-file
@@ -14,8 +14,10 @@ echo "generating $out"
# autogenerated file: run scripts/generate-eslint-error-ignore-file to update.
EOF
-
- ./node_modules/.bin/eslint --no-ignore -f json src test |
+
+ ./node_modules/.bin/eslint -f json src test |
jq -r '.[] | select((.errorCount + .warningCount) > 0) | .filePath' |
sed -e 's/.*matrix-react-sdk\///';
} > "$out"
+# also append rules from eslintignore file
+cat .eslintignore >> $out
diff --git a/src/Avatar.js b/src/Avatar.js
index 5a330c31e9..217b196348 100644
--- a/src/Avatar.js
+++ b/src/Avatar.js
@@ -102,6 +102,8 @@ export function getInitialLetter(name) {
}
export function avatarUrlForRoom(room, width, height, resizeMethod) {
+ if (!room) return null; // null-guard
+
const explicitRoomAvatar = room.getAvatarUrl(
MatrixClientPeg.get().getHomeserverUrl(),
width,
diff --git a/src/BasePlatform.js b/src/BasePlatform.js
index 14e34a1f40..a935f4a767 100644
--- a/src/BasePlatform.js
+++ b/src/BasePlatform.js
@@ -162,4 +162,6 @@ export default class BasePlatform {
getEventIndexingManager(): BaseEventIndexManager | null {
return null;
}
+
+ setLanguage(preferredLangs: string[]) {}
}
diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js
index 236aa0157e..7dd68e5c61 100644
--- a/src/HtmlUtils.js
+++ b/src/HtmlUtils.js
@@ -160,7 +160,7 @@ const transformTags = { // custom to matrix
delete attribs.target;
}
}
- attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
+ attribs.rel = 'noreferrer noopener'; // https://mathiasbynens.github.io/rel-noopener/
return { tagName, attribs };
},
'img': function(tagName, attribs) {
diff --git a/src/Markdown.js b/src/Markdown.js
index 437ceec88b..fb1f8bf0ea 100644
--- a/src/Markdown.js
+++ b/src/Markdown.js
@@ -136,7 +136,7 @@ export default class Markdown {
// thus opening in a new tab.
if (externalLinks) {
attrs.push(['target', '_blank']);
- attrs.push(['rel', 'noopener']);
+ attrs.push(['rel', 'noreferrer noopener']);
}
this.tag('a', attrs);
} else {
diff --git a/src/Rooms.js b/src/Rooms.js
index f65e0ff218..218e970f35 100644
--- a/src/Rooms.js
+++ b/src/Rooms.js
@@ -23,7 +23,7 @@ import {MatrixClientPeg} from './MatrixClientPeg';
* of aliases. Otherwise return null;
*/
export function getDisplayAliasForRoom(room) {
- return room.getCanonicalAlias() || room.getAliases()[0];
+ return room.getCanonicalAlias() || room.getAltAliases()[0];
}
/**
diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js
index d534fe5d1d..10a3848dda 100644
--- a/src/actions/RoomListActions.js
+++ b/src/actions/RoomListActions.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import { asyncAction } from './actionCreators';
-import RoomListStore from '../stores/RoomListStore';
+import RoomListStore, {TAG_DM} from '../stores/RoomListStore';
import Modal from '../Modal';
import * as Rooms from '../Rooms';
import { _t } from '../languageHandler';
@@ -73,11 +73,11 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex,
const roomId = room.roomId;
// Evil hack to get DMs behaving
- if ((oldTag === undefined && newTag === 'im.vector.fake.direct') ||
- (oldTag === 'im.vector.fake.direct' && newTag === undefined)
+ if ((oldTag === undefined && newTag === TAG_DM) ||
+ (oldTag === TAG_DM && newTag === undefined)
) {
return Rooms.guessAndSetDMRoom(
- room, newTag === 'im.vector.fake.direct',
+ room, newTag === TAG_DM,
).catch((err) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set direct chat tag " + err);
@@ -91,10 +91,10 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex,
const hasChangedSubLists = oldTag !== newTag;
// More evilness: We will still be dealing with moving to favourites/low prio,
- // but we avoid ever doing a request with 'im.vector.fake.direct`.
+ // but we avoid ever doing a request with TAG_DM.
//
// if we moved lists, remove the old tag
- if (oldTag && oldTag !== 'im.vector.fake.direct' &&
+ if (oldTag && oldTag !== TAG_DM &&
hasChangedSubLists
) {
const promiseToDelete = matrixClient.deleteRoomTag(
@@ -112,7 +112,7 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex,
}
// if we moved lists or the ordering changed, add the new tag
- if (newTag && newTag !== 'im.vector.fake.direct' &&
+ if (newTag && newTag !== TAG_DM &&
(hasChangedSubLists || metaData)
) {
// metaData is the body of the PUT to set the tag, so it must
diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
index f89fb17448..3a480a2579 100644
--- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
+++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
@@ -53,7 +53,6 @@ function selectText(target) {
*/
export default class CreateKeyBackupDialog extends React.PureComponent {
static propTypes = {
- secureSecretStorage: PropTypes.bool,
onFinished: PropTypes.func.isRequired,
}
@@ -65,7 +64,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
this._setZxcvbnResultTimeout = null;
this.state = {
- secureSecretStorage: props.secureSecretStorage,
+ secureSecretStorage: null,
phase: PHASE_PASSPHRASE,
passPhrase: '',
passPhraseConfirm: '',
@@ -73,23 +72,20 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
downloaded: false,
zxcvbnResult: null,
};
-
- if (this.state.secureSecretStorage === undefined) {
- this.state.secureSecretStorage =
- SettingsStore.isFeatureEnabled("feature_cross_signing");
- }
-
- // If we're using secret storage, skip ahead to the backing up step, as
- // `accessSecretStorage` will handle passphrases as needed.
- if (this.state.secureSecretStorage) {
- this.state.phase = PHASE_BACKINGUP;
- }
}
- componentDidMount() {
+ async componentDidMount() {
+ const cli = MatrixClientPeg.get();
+ const secureSecretStorage = (
+ SettingsStore.isFeatureEnabled("feature_cross_signing") &&
+ await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")
+ );
+ this.setState({ secureSecretStorage });
+
// If we're using secret storage, skip ahead to the backing up step, as
// `accessSecretStorage` will handle passphrases as needed.
- if (this.state.secureSecretStorage) {
+ if (secureSecretStorage) {
+ this.setState({ phase: PHASE_BACKINGUP });
this._createBackup();
}
}
diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js
index fccf1e3524..a0f670e769 100644
--- a/src/autocomplete/RoomProvider.js
+++ b/src/autocomplete/RoomProvider.js
@@ -23,7 +23,6 @@ import AutocompleteProvider from './AutocompleteProvider';
import {MatrixClientPeg} from '../MatrixClientPeg';
import QueryMatcher from './QueryMatcher';
import {PillCompletion} from './Components';
-import {getDisplayAliasForRoom} from '../Rooms';
import * as sdk from '../index';
import _sortBy from 'lodash/sortBy';
import {makeRoomPermalink} from "../utils/permalinks/Permalinks";
@@ -40,11 +39,19 @@ function score(query, space) {
}
}
+function matcherObject(room, displayedAlias, matchName = "") {
+ return {
+ room,
+ matchName,
+ displayedAlias,
+ };
+}
+
export default class RoomProvider extends AutocompleteProvider {
constructor() {
super(ROOM_REGEX);
this.matcher = new QueryMatcher([], {
- keys: ['displayedAlias', 'name'],
+ keys: ['displayedAlias', 'matchName'],
});
}
@@ -56,16 +63,16 @@ export default class RoomProvider extends AutocompleteProvider {
const {command, range} = this.getCurrentCommand(query, selection, force);
if (command) {
// the only reason we need to do this is because Fuse only matches on properties
- let matcherObjects = client.getVisibleRooms().filter(
- (room) => !!room && !!getDisplayAliasForRoom(room),
- ).map((room) => {
- return {
- room: room,
- name: room.name,
- displayedAlias: getDisplayAliasForRoom(room),
- };
- });
-
+ let matcherObjects = client.getVisibleRooms().reduce((aliases, room) => {
+ if (room.getCanonicalAlias()) {
+ aliases = aliases.concat(matcherObject(room, room.getCanonicalAlias(), room.name));
+ }
+ if (room.getAltAliases().length) {
+ const altAliases = room.getAltAliases().map(alias => matcherObject(room, alias));
+ aliases = aliases.concat(altAliases);
+ }
+ return aliases;
+ }, []);
// Filter out any matches where the user will have also autocompleted new rooms
matcherObjects = matcherObjects.filter((r) => {
const tombstone = r.room.currentState.getStateEvents("m.room.tombstone", "");
@@ -84,16 +91,16 @@ export default class RoomProvider extends AutocompleteProvider {
completions = _sortBy(completions, [
(c) => score(matchedString, c.displayedAlias),
(c) => c.displayedAlias.length,
- ]).map((room) => {
- const displayAlias = getDisplayAliasForRoom(room.room) || room.roomId;
+ ]);
+ completions = completions.map((room) => {
return {
- completion: displayAlias,
- completionId: displayAlias,
+ completion: room.displayedAlias,
+ completionId: room.room.roomId,
type: "room",
suffix: ' ',
- href: makeRoomPermalink(displayAlias),
+ href: makeRoomPermalink(room.displayedAlias),
component: (
-
;
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 229c741310..339ea279ee 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -1175,6 +1175,7 @@ export default createReactClass({
* Called when a new logged in session has started
*/
_onLoggedIn: async function() {
+ ThemeController.isLogin = false;
this.setStateForNewView({ view: VIEWS.LOGGED_IN });
if (MatrixClientPeg.currentUserIsJustRegistered()) {
MatrixClientPeg.setJustRegisteredUserId(null);
@@ -1374,7 +1375,8 @@ export default createReactClass({
cancelButton: _t('Dismiss'),
onFinished: (confirmed) => {
if (confirmed) {
- window.open(consentUri, '_blank');
+ const wnd = window.open(consentUri, '_blank');
+ wnd.opener = null;
}
},
}, null, true);
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index b8b11fbb31..d0e35e1c2b 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -873,6 +873,11 @@ class CreationGrouper {
}
getTiles() {
+ // If we don't have any events to group, don't even try to group them. The logic
+ // below assumes that we have a group of events to deal with, but we might not if
+ // the events we were supposed to group were redacted.
+ if (!this.events || !this.events.length) return [];
+
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventListSummary = sdk.getComponent('views.elements.EventListSummary');
@@ -959,6 +964,11 @@ class MemberGrouper {
}
getTiles() {
+ // If we don't have any events to group, don't even try to group them. The logic
+ // below assumes that we have a group of events to deal with, but we might not if
+ // the events we were supposed to group were redacted.
+ if (!this.events || !this.events.length) return [];
+
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index acc87d9616..edd916697a 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -342,7 +342,7 @@ export default createReactClass({
peekLoading: false,
});
this._onRoomLoaded(room);
- }, (err) => {
+ }).catch((err) => {
if (this.unmounted) {
return;
}
@@ -355,7 +355,7 @@ export default createReactClass({
// This won't necessarily be a MatrixError, but we duck-type
// here and say if it's got an 'errcode' key with the right value,
// it means we can't peek.
- if (err.errcode == "M_GUEST_ACCESS_FORBIDDEN") {
+ if (err.errcode === "M_GUEST_ACCESS_FORBIDDEN" || err.errcode === 'M_FORBIDDEN') {
// This is fine: the room just isn't peekable (we assume).
this.setState({
peekLoading: false,
@@ -365,8 +365,6 @@ export default createReactClass({
}
});
} else if (room) {
- //viewing a previously joined room, try to lazy load members
-
// Stop peeking because we have joined this room previously
MatrixClientPeg.get().stopPeeking();
this.setState({isPeeking: false});
@@ -460,8 +458,6 @@ export default createReactClass({
// (We could use isMounted, but facebook have deprecated that.)
this.unmounted = true;
- SettingsStore.unwatchSetting(this._ciderWatcherRef);
-
// update the scroll map before we get unmounted
if (this.state.roomId) {
RoomScrollStateStore.setScrollState(this.state.roomId, this._getScrollState());
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index c8b2a1ea9c..24e4726416 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -481,7 +481,7 @@ export default createReactClass({
"Either use HTTPS or enable unsafe scripts.", {},
{
'a': (sub) => {
- return
{ sub }
@@ -496,11 +496,10 @@ export default createReactClass({
"homeserver's SSL certificate is trusted, and that a browser extension " +
"is not blocking requests.", {},
{
- 'a': (sub) => {
- return
+ 'a': (sub) =>
+
{ sub }
- ;
- },
+ ,
},
) }
;
diff --git a/src/components/views/auth/AuthFooter.js b/src/components/views/auth/AuthFooter.js
index 4076141606..1309800772 100644
--- a/src/components/views/auth/AuthFooter.js
+++ b/src/components/views/auth/AuthFooter.js
@@ -26,7 +26,7 @@ export default createReactClass({
render: function() {
return (
{_t( + "Your homeserver does not support cross-signing.", + )}
; + } else if (enabledForAccount && crossSigningPublicKeysOnDevice) { summarisedStatus =✅ {_t( "Cross-signing and secret storage are enabled.", )}
; @@ -149,19 +158,28 @@ export default class CrossSigningPanel extends React.PureComponent { )}; } + let resetButton; + if (enabledForAccount) { + resetButton = ( +/help
to list available commands. Did you mean to send this as a message?": "Sie können /help
benutzen, um verfügbare Befehle aufzulisten. Wollten Sie dies als Nachricht senden?",
+ "Direct message": "Direkte Nachricht",
+ "Set a room alias to easily share your room with other people.": "Setze ein Raum-Alias, um deinen Raum einfach mit anderen Personen zu teilen.",
+ "Suggestions": "Vorschläge",
+ "Recently Direct Messaged": "Kürzlich direkt verschickt",
+ "If you can't find someone, ask them for their username, share your username (%(userId)s) or profile link.": "Wenn Sie niemanden finden können, fragen Sie nach deren Benutzernamen, teilen Sie ihren Benutzernamen (%(userId)s) oder Profil-Link.",
+ "Go": "Los",
+ "If you can't find someone, ask them for their username (e.g. @user:server.com) or share this room.": "Wenn Sie niemanden finden können, fragen Sie nach deren Benutzernamen (z.B. @benutzer:server.de) oder teilen Sie diesen Raum.",
+ "Command Help": "Befehl Hilfe",
+ "To help us prevent this in future, please send us logs.": "Um uns zu helfen, dies in Zukunft zu vermeiden, senden Sie uns bitte Logs.",
+ "We recommend you go through the verification process for each session to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "Wir empfehlen Ihnen, den Verifizierungsprozess für jede Sitzung zu durchlaufen, um zu bestätigen, dass sie ihrem rechtmäßigen Eigentümer gehören, aber Sie können die Nachricht auch ohne Verifizierung erneut senden, wenn Sie dies bevorzugen.",
+ "Notification settings": "Benachrichtigungseinstellungen",
+ "Help": "Hilfe",
+ "Filter": "Filter",
+ "Filter rooms…": "Räume filtern…",
+ "You have %(count)s unread notifications in a prior version of this room.|one": "Sie haben %(count)s ungelesene Benachrichtigungen in einer früheren Version dieses Raumes.",
+ "Go Back": "Gehe zurück",
+ "Notification Autocomplete": "Benachrichtigung Autovervollständigen",
+ "If disabled, messages from encrypted rooms won't appear in search results.": "Wenn deaktiviert, werden Nachrichten von verschlüsselten Räumen nicht in den Ergebnissen auftauchen.",
+ "This user has not verified all of their sessions.": "Dieser Benutzer hat nicht alle seine Sitzungen verifiziert.",
+ "You have verified this user. This user has verified all of their sessions.": "Sie haben diesen Benutzer verifiziert. Dieser Benutzer hat alle seine Sitzungen verifiziert.",
+ "Some sessions for this user are not trusted": "Einige Sitzungen für diesen Benutzer sind nicht vertrauenswürdig",
+ "All sessions for this user are trusted": "Alle Sitzungen für diesen Benutzer sind vertrauenswürdig",
+ "Some sessions in this encrypted room are not trusted": "Einige Sitzungen in diesem verschlüsselten Raum sind nicht vertrauenswürdig",
+ "All sessions in this encrypted room are trusted": "Alle Sitzungen in diesem verschlüsselten Raum sind vertrauenswürdig",
+ "Your key share request has been sent - please check your other sessions for key share requests.": "Ihre Anfrage zur Schlüssel-Teilung wurde gesendet - bitte überprüfen Sie Ihre anderen Sitzungen auf Anfragen zur Schlüssel-Teilung.",
+ "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Anfragen zum Teilen von Schlüsseln werden automatisch an Ihre anderen Sitzungen gesendet. Wenn Sie die Anfragen zum Teilen von Schlüsseln in Ihren anderen Sitzungen abgelehnt oder abgewiesen haben, klicken Sie hier, um die Schlüssel für diese Sitzung erneut anzufordern.",
+ "If your other sessions do not have the key for this message you will not be able to decrypt them.": "Wenn Ihre anderen Sitzungen nicht über den Schlüssel für diese Nachricht verfügen, können Sie sie nicht entschlüsseln.",
+ "/help
to list available commands. Did you mean to send this as a message?": "Type /help
om alle opdrachten te zien. Was het uw bedoeling dit als bericht te sturen?",
+ "You can use /help
to list available commands. Did you mean to send this as a message?": "Typ /help
om alle opdrachten te zien. Was het uw bedoeling dit als bericht te sturen?",
"Help": "Hulp",
"Set up encryption": "Versleuteling instellen",
"Unverified session": "Ongeverifieerde sessie",
- "This action requires accessing the default identity server @bot:*
would ignore all users that have the name 'bot' on any server.": "Geef hier te negeren gebruikers en servers in. Asterisken staan voor willekeurige tekenreeksen; zo leidt @bot:*
tot het negeren van gebruikers die 'bot' heten op alle servers.",
+ "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Momenteel stelt een wachtwoordswijziging alle berichtsleutels in alle sessies opnieuw in, en maakt zo oude versleutelde berichten onleesbaar - tenzij u uw sleutels eerst wegschrijft, en na afloop weer inleest. Dit zal verbeterd worden.",
+ "Add users and servers you want to ignore here. Use asterisks to have Riot match any characters. For example, @bot:*
would ignore all users that have the name 'bot' on any server.": "Geef hier te negeren gebruikers en servers in. Asterisken staan voor willekeurige tekenreeksen; zo leidt @bot:*
tot het negeren van alle gebruikers die ‘bot’ heten op alle servers.",
"in memory": "in het geheugen",
"not found": "niet gevonden",
"Your homeserver does not support session management.": "Uw thuisserver ondersteunt geen sessiebeheer.",
"Unable to load session list": "Kan sessielijst niet laden",
- "Delete %(count)s sessions|other": "Verwijder %(count)s sessies",
- "Delete %(count)s sessions|one": "Verwijder %(count)s sessie"
+ "Delete %(count)s sessions|other": "%(count)s sessies verwijderen",
+ "Delete %(count)s sessions|one": "%(count)s sessie verwijderen",
+ "The version of Riot": "De versie van Riot",
+ "Whether you're using Riot on a device where touch is the primary input mechanism": "Of u Riot op een apparaat gebruikt waarop een aanraakscherm de voornaamste invoermethode is",
+ "Whether you're using Riot as an installed Progressive Web App": "Of u Riot gebruikt als een geïnstalleerde Progressive-Web-App",
+ "Your user agent": "Uw gebruikersagent",
+ "The information being sent to us to help make Riot better includes:": "De informatie die naar ons wordt verstuurd om Riot te verbeteren bevat:",
+ "If you cancel now, you won't complete verifying the other user.": "Als u nu annuleert zult u de andere gebruiker niet verifiëren.",
+ "If you cancel now, you won't complete verifying your other session.": "Als u nu annuleert zult u uw andere sessie niet verifiëren.",
+ "If you cancel now, you won't complete your secret storage operation.": "Als u nu annuleert zal de sleutelopslag worden afgebroken.",
+ "Cancel entering passphrase?": "Wachtwoordinvoer annuleren?",
+ "Show typing notifications": "Typmeldingen weergeven",
+ "Verify this session by completing one of the following:": "Verifieer deze sessie door een van het volgende te doen:",
+ "Scan this unique code": "Scan deze unieke code",
+ "or": "of",
+ "Compare unique emoji": "Vergelijk unieke emoji",
+ "Compare a unique set of emoji if you don't have a camera on either device": "Vergelijk een unieke lijst met emoji als geen van beide apparaten een camera heeft",
+ "Start": "Start",
+ "Securely cache encrypted messages locally for them to appear in search results.": "Sla versleutelde berichten beveiligd op om ze weer te geven in zoekresultaten.",
+ "Enable": "Inschakelen",
+ "Connecting to integration manager...": "Verbinding maken met de integratiebeheerder…",
+ "Cannot connect to integration manager": "Kan geen verbinding maken met de integratiebeheerder",
+ "The integration manager is offline or it cannot reach your homeserver.": "De integratiebeheerder is offline of kan uw thuisserver niet bereiken.",
+ "This session is backing up your keys. ": "Deze sessie maakt back-ups van uw sleutels. ",
+ "not stored": "niet opgeslagen",
+ "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Uw wachtwoord is gewijzigd. U zult geen pushmeldingen op uw andere sessies meer ontvangen, totdat u zichzelf daarop opnieuw aanmeldt",
+ "Ignored/Blocked": "Genegeerd/geblokkeerd",
+ "Error adding ignored user/server": "Fout bij het toevoegen van een genegeerde gebruiker/server",
+ "Something went wrong. Please try again or view your console for hints.": "Er is iets fout gegaan. Probeer het opnieuw of bekijk de console om voor meer informatie.",
+ "Error subscribing to list": "Fout bij het abonneren op de lijst",
+ "Please verify the room ID or alias and try again.": "Controleer de gespreks-ID of -(bij)naam en probeer het opnieuw.",
+ "Error removing ignored user/server": "Fout bij het verwijderen van genegeerde gebruiker/server",
+ "Error unsubscribing from list": "Fout bij het opzeggen van een abonnement op de lijst",
+ "Please try again or view your console for hints.": "Probeer het opnieuw of bekijk de console voor meer informatie.",
+ "None": "Geen",
+ "You have not ignored anyone.": "U heeft niemand genegeerd.",
+ "You are currently ignoring:": "U negeert op dit moment:",
+ "You are not subscribed to any lists": "U heeft geen abonnement op een lijst",
+ "Unsubscribe": "Abonnement opzeggen",
+ "View rules": "Bekijk regels",
+ "You are currently subscribed to:": "U heeft een abonnement op:",
+ "⚠ These settings are meant for advanced users.": "⚠ Deze instellingen zijn bedoeld voor gevorderde gebruikers.",
+ "Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Het negeren van gebruikers gaat via banlijsten. Deze bevatten regels over wie verbannen moet worden. Het abonneren op een banlijst betekent dat u de gebruikers/servers die op de lijst staan niet meer zult zien.",
+ "Personal ban list": "Persoonlijke banlijst",
+ "Your personal ban list holds all the users/servers you personally don't want to see messages from. After ignoring your first user/server, a new room will show up in your room list named 'My Ban List' - stay in this room to keep the ban list in effect.": "Uw persoonlijke banlijst bevat alle gebruikers/server waar u geen berichten meer van wilt zien. Nadat u een gebruiker/server heeft genegeerd, zal er een nieuw gesprek worden aangemaakt met de naam ‘Mijn banlijst’. Om de lijst actief te houden dient u het gesprek niet te verlaten.",
+ "Server or user ID to ignore": "Server of gebruikers-ID om te negeren",
+ "eg: @bot:* or example.org": "bijvoorbeeld: @bot:* of voorbeeld.org",
+ "Subscribed lists": "Abonnementen op lijsten",
+ "Subscribing to a ban list will cause you to join it!": "Wanneer u zich abonneert op een banlijst zal u eraan worden toegevoegd!",
+ "If this isn't what you want, please use a different tool to ignore users.": "Als u dit niet wilt kunt u een andere methode gebruiken om gebruikers te negeren.",
+ "Room ID or alias of ban list": "Gespreks-ID of (bij)naam van banlijst",
+ "Subscribe": "Abonneren",
+ "Enable desktop notifications for this session": "Bureaubladmeldingen inschakelen voor deze sessie",
+ "Enable audible notifications for this session": "Meldingen met geluid inschakelen voor deze sessie",
+ "You should:": "U zou best:",
+ "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "uw browserextensies bekijken voor extensies die mogelijk de identiteitsserver blokkeren (zoals Privacy Badger)",
+ "contact the administrators of identity server \n Use the long description to introduce new members to the community, or distribute\n some important links\n
\n\n You can even use 'img' tags\n
\n": "\n Bruk den Lange Skildringa for å ynskja nye medlemer velkomen, eller gje ut viktige lenkjer\n
\n\n Du kan til og med bruka 'img'-merkelappar!\n
\n", - "Add rooms to the community summary": "Legg rom til i samfunnsoppsamanfattinga", + "\n Use the long description to introduce new members to the community, or distribute\n some important links\n
\n\n You can even use 'img' tags\n
\n": "\n Bruk den Lange Skildringa for å ynskja nye medlemer velkomen, eller gje ut viktige lenkjer\n
\n\n Du kan til og med bruka 'img' HTML-taggar!\n
\n", + "Add rooms to the community summary": "Legg rom til i samandraget for fellesskapet", "Which rooms would you like to add to this summary?": "Kva rom ynskjer du å leggja til i samanfattinga?", "Add to summary": "Legg til i samanfattinga", "Failed to add the following rooms to the summary of %(groupId)s:": "Fekk ikkje til å leggja dei fylgjande romma til i samanfattinga av %(groupId)s:", "Add a Room": "Legg eit Rom til", "Failed to remove the room from the summary of %(groupId)s": "Fekk ikkje til å fjerna rommet frå samanfattinga av %(groupId)s", "The room '%(roomName)s' could not be removed from the summary.": "Rommet '%(roomName)s' lét seg ikkje fjerna frå samanfattinga.", - "Add users to the community summary": "Legg brukarar til i samfunnsamanfattinga", + "Add users to the community summary": "Legg brukarar til i samandraget for fellesskapet", "Who would you like to add to this summary?": "Kven vil du leggja til i samanfattinga?", "Failed to add the following users to the summary of %(groupId)s:": "Fekk ikkje til å leggja fylgjande brukarar til i samanfattinga av %(groupId)s:", "Add a User": "Legg ein Brukar til", "Failed to remove a user from the summary of %(groupId)s": "Fekk ikkje til å fjerna brukaren frå samanfattinga av %(groupId)s", "The user '%(displayName)s' could not be removed from the summary.": "Brukaren '%(displayName)s' lét seg ikkje fjerna frå samanfattinga.", "Failed to upload image": "Fekk ikkje til å lasta biletet opp", - "Failed to update community": "Fekk ikkje til å oppdatera samfunnet", + "Failed to update community": "Fekk ikkje til å oppdatera fellesskapet", "Unable to accept invite": "Fekk ikkje til å seia ja til innbydinga", - "Unable to join community": "Fekk ikkje til å fara inn i samfunnet", - "Leave Community": "Far frå Samfunnet", + "Unable to join community": "Fekk ikkje til å bli med i fellesskapet", + "Leave Community": "Forlat fellesskapet", "Leave %(groupName)s?": "Far frå %(groupName)s?", - "Unable to leave community": "Fekk ikkje til å fara frå samfunnet", - "Community Settings": "Samfunninnstillingar", - "Changes made to your community