diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml new file mode 100644 index 0000000000..04b047436b --- /dev/null +++ b/.buildkite/pipeline.yaml @@ -0,0 +1,60 @@ +steps: + - label: ":eslint: Lint" + command: + - "yarn install" + - "yarn lintwithexclusions" + plugins: + - docker#v3.0.1: + image: "node:10" + +# - label: ":chains: End-to-End Tests" +# command: +# # TODO: Remove hacky chmod for BuildKite +# - "chmod +x ./scripts/ci/*.sh" +# - "chmod +x ./scripts/*" +# - "sudo apt-get install build-essential python2.7-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev" +# - "./scripts/ci/install-deps.sh" +# - "./scripts/ci/end-to-end-tests.sh" +# plugins: +# - docker#v3.0.1: +# image: "node:10" + + - label: ":karma: Tests" + command: + # Install chrome + - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" + - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" + - "apt-get update" + - "apt-get install -y google-chrome-stable" + # Run tests + # TODO: Remove hacky chmod for BuildKite + - "chmod +x ./scripts/ci/*.sh" + - "chmod +x ./scripts/*" + - "./scripts/ci/install-deps.sh" + - "./scripts/ci/unit-tests.sh" + env: + CHROME_BIN: "/usr/bin/google-chrome-stable" + plugins: + - docker#v3.0.1: + image: "node:10" + propagate-environment: true + + - label: "🔧 Riot Tests" + command: + # Install chrome + - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" + - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" + - "apt-get update" + - "apt-get install -y google-chrome-stable" + # Run tests + # TODO: Remove hacky chmod for BuildKite + - "chmod +x ./scripts/ci/*.sh" + - "chmod +x ./scripts/*" + - "./scripts/ci/install-deps.sh" + - "./scripts/ci/riot-unit-tests.sh" + env: + CHROME_BIN: "/usr/bin/google-chrome-stable" + plugins: + - docker#v3.0.1: + image: "node:10" + propagate-environment: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ebf36658d5..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -# we need trusty for the chrome addon -dist: trusty - -# we don't need sudo, so can run in a container, which makes startup much -# quicker. -# -# unfortunately we do temporarily require sudo as a workaround for -# https://github.com/travis-ci/travis-ci/issues/8836 -sudo: required - -language: node_js -node_js: - - node # Latest stable version of nodejs. -addons: - chrome: stable -before_install: - - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0 - - export PATH=$HOME/.yarn/bin:$PATH -install: - - ./scripts/travis/install-deps.sh -matrix: - include: - - name: Linting Checks - script: - # run the linter, but exclude any files known to have errors or warnings. - - yarn lintwithexclusions - # - name: End-to-End Tests - # if: branch = develop - # install: - # - sudo apt-get install build-essential python2.7-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev - # script: - # - ./scripts/travis/end-to-end-tests.sh - - name: Unit Tests - script: - - ./scripts/travis/unit-tests.sh - - name: Riot-web Unit Tests - script: - - ./scripts/travis/riot-unit-tests.sh diff --git a/karma.conf.js b/karma.conf.js index 5e7fe76d56..b687be78fa 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -135,9 +135,10 @@ module.exports = function (config) { ], customLaunchers: { - 'ChromeHeadless': { + 'VectorChromeHeadless': { base: 'Chrome', flags: [ + '--no-sandbox', // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md '--headless', '--disable-gpu', diff --git a/package.json b/package.json index 0fa4a829de..f1fb365a65 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "lintwithexclusions": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test", "clean": "rimraf lib", "prepare": "yarn clean && yarn build && git rev-parse HEAD > git-revision.txt", - "test": "karma start --single-run=true --browsers ChromeHeadless", + "test": "karma start --single-run=true --browsers VectorChromeHeadless", "test-multi": "karma start" }, "dependencies": { @@ -131,7 +131,7 @@ "flow-parser": "^0.57.3", "jest-mock": "^23.2.0", "karma": "^4.0.1", - "karma-chrome-launcher": "^0.2.3", + "karma-chrome-launcher": "^2.2.0", "karma-cli": "^1.0.1", "karma-junit-reporter": "^2.0.0", "karma-logcapture-reporter": "0.0.1", diff --git a/res/css/views/avatars/_BaseAvatar.scss b/res/css/views/avatars/_BaseAvatar.scss index ee2d9c190f..91b2d6c426 100644 --- a/res/css/views/avatars/_BaseAvatar.scss +++ b/res/css/views/avatars/_BaseAvatar.scss @@ -16,6 +16,16 @@ limitations under the License. .mx_BaseAvatar { position: relative; + // In at least Firefox, the case of relative positioned inline elements + // (such as mx_BaseAvatar) with absolute positioned children (such as + // mx_BaseAvatar_initial) is a dark corner full of spider webs. It will give + // different results during full reflow of the page vs. incremental reflow + // of small portions. While that's surely a browser bug, we can avoid it by + // using `inline-block` instead of the default `inline`. + // https://github.com/vector-im/riot-web/issues/5594 + // https://bugzilla.mozilla.org/show_bug.cgi?id=1535053 + // https://bugzilla.mozilla.org/show_bug.cgi?id=255139 + display: inline-block; } .mx_BaseAvatar_initial { diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index 68a9d61edb..44528a5624 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -22,10 +22,20 @@ limitations under the License. } .mx_EntityTile:hover { - background-image: url('$(res)/img/member_chevron.png'); - background-position: center right 10px; - background-repeat: no-repeat; padding-right: 30px; + position: relative; // to keep the chevron aligned +} + +.mx_EntityTile:hover::before { + content: ""; + position: absolute; + top: calc(50% - 8px); // center + right: 10px; + mask: url('$(res)/img/member_chevron.png'); + mask-repeat: no-repeat; + width: 16px; + height: 16px; + background-color: $rightpanel-button-color; } .mx_EntityTile .mx_PresenceLabel { @@ -92,19 +102,19 @@ limitations under the License. .mx_EntityTile_unavailable .mx_EntityTile_avatar, .mx_EntityTile_unavailable .mx_EntityTile_name, .mx_EntityTile_offline_beenactive .mx_EntityTile_avatar, -.mx_EntityTile_offline_beenactive .mx_EntityTile_name, +.mx_EntityTile_offline_beenactive .mx_EntityTile_name { opacity: 0.5; } .mx_EntityTile_offline_neveractive .mx_EntityTile_avatar, -.mx_EntityTile_offline_neveractive .mx_EntityTile_name, +.mx_EntityTile_offline_neveractive .mx_EntityTile_name { opacity: 0.25; } .mx_EntityTile_unknown .mx_EntityTile_avatar, -.mx_EntityTile_unknown .mx_EntityTile_name, +.mx_EntityTile_unknown .mx_EntityTile_name { opacity: 0.25; } diff --git a/scripts/travis/build.sh b/scripts/ci/build.sh old mode 100755 new mode 100644 similarity index 82% rename from scripts/travis/build.sh rename to scripts/ci/build.sh index 862a3feaa9..0b1fa23093 --- a/scripts/travis/build.sh +++ b/scripts/ci/build.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# script which is run by the travis build (after `yarn test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. diff --git a/scripts/travis/end-to-end-tests.sh b/scripts/ci/end-to-end-tests.sh old mode 100755 new mode 100644 similarity index 84% rename from scripts/travis/end-to-end-tests.sh rename to scripts/ci/end-to-end-tests.sh index 0c728be509..d0b1a30ce2 --- a/scripts/travis/end-to-end-tests.sh +++ b/scripts/ci/end-to-end-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# script which is run by the travis build (after `yarn test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. @@ -9,7 +9,7 @@ set -ev RIOT_WEB_DIR=riot-web REACT_SDK_DIR=`pwd` -scripts/travis/build.sh +scripts/ci/build.sh # run end to end tests scripts/fetchdep.sh matrix-org matrix-react-end-to-end-tests master pushd matrix-react-end-to-end-tests diff --git a/scripts/travis/install-deps.sh b/scripts/ci/install-deps.sh old mode 100755 new mode 100644 similarity index 100% rename from scripts/travis/install-deps.sh rename to scripts/ci/install-deps.sh diff --git a/scripts/travis/riot-unit-tests.sh b/scripts/ci/riot-unit-tests.sh old mode 100755 new mode 100644 similarity index 65% rename from scripts/travis/riot-unit-tests.sh rename to scripts/ci/riot-unit-tests.sh index ca53dc9268..215af13030 --- a/scripts/travis/riot-unit-tests.sh +++ b/scripts/ci/riot-unit-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# script which is run by the travis build (after `yarn test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. @@ -8,7 +8,7 @@ set -ev RIOT_WEB_DIR=riot-web -scripts/travis/build.sh +scripts/ci/build.sh pushd "$RIOT_WEB_DIR" yarn test popd diff --git a/scripts/ci/unit-tests.sh b/scripts/ci/unit-tests.sh new file mode 100644 index 0000000000..5b86190963 --- /dev/null +++ b/scripts/ci/unit-tests.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# +# script which is run by the CI build (after `yarn test`). +# +# clones riot-web develop and runs the tests against our version of react-sdk. + +set -ev + +scripts/ci/build.sh +yarn test diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 95fc4b0603..6fb50e7cea 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -17,10 +17,11 @@ clone() { fi } + # Try the PR author's branch in case it exists on the deps as well. -clone $TRAVIS_PULL_REQUEST_BRANCH +clone $BUILDKITE_BRANCH # Try the target branch of the push or PR. -clone $TRAVIS_BRANCH +clone $BUILDKITE_PULL_REQUEST_BASE_BRANCH # Try the current branch from Jenkins. clone `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` # Use the default branch as the last resort. diff --git a/scripts/travis/unit-tests.sh b/scripts/travis/unit-tests.sh deleted file mode 100755 index fe3e383c0a..0000000000 --- a/scripts/travis/unit-tests.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# -# script which is run by the travis build (after `yarn test`). -# -# clones riot-web develop and runs the tests against our version of react-sdk. - -set -ev - -scripts/travis/build.sh -CHROME_BIN='/usr/bin/google-chrome-stable' yarn test diff --git a/src/components/structures/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js index 28521cb1b7..c6abba4eb3 100644 --- a/src/components/structures/CompatibilityPage.js +++ b/src/components/structures/CompatibilityPage.js @@ -48,19 +48,13 @@ module.exports = React.createClass({

{ _t( - 'Please install Chrome or Firefox ' + - 'for the best experience.', + 'Please install Chrome, Firefox, ' + + 'or Safari for the best experience.', {}, { 'chromeLink': (sub) => {sub}, - 'firefoxLink': (sub) => {sub}, - }, - )} - { _t('Safari and Opera work too.', - {}, - { - 'safariLink': (sub) => {sub}, - 'operaLink': (sub) => {sub}, + 'firefoxLink': (sub) => {sub}, + 'safariLink': (sub) => {sub}, }, )}

diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js index 4e33f0a22d..d99204e40a 100644 --- a/src/components/structures/CustomRoomTagPanel.js +++ b/src/components/structures/CustomRoomTagPanel.js @@ -84,7 +84,7 @@ class CustomRoomTagTile extends React.Component { render() { const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const RoomTooltip = sdk.getComponent('rooms.RoomTooltip'); + const Tooltip = sdk.getComponent('rooms.Tooltip'); const tag = this.props.tag; const avatarHeight = 40; @@ -103,7 +103,7 @@ class CustomRoomTagTile extends React.Component { } const tip = (this.state.hover ? - : + :
); return ( diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index 4275a24b49..1784ab61c3 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -70,6 +70,11 @@ module.exports = React.createClass({ fieldErrors: {}, // The ISO2 country code selected in the phone number entry phoneCountry: this.props.defaultPhoneCountry, + username: "", + email: "", + phoneNumber: "", + password: "", + passwordConfirm: "", }; }, @@ -89,7 +94,7 @@ module.exports = React.createClass({ const self = this; if (this.allFieldsValid()) { - if (this.refs.email.value == '') { + if (this.state.email == '') { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); Modal.createTrackedDialog('If you don\'t specify an email address...', '', QuestionDialog, { title: _t("Warning!"), @@ -112,13 +117,13 @@ module.exports = React.createClass({ }, _doSubmit: function(ev) { - const email = this.refs.email.value.trim(); + const email = this.state.email.trim(); const promise = this.props.onRegisterClick({ - username: this.refs.username.value.trim(), - password: this.refs.password.value.trim(), + username: this.state.username.trim(), + password: this.state.password.trim(), email: email, phoneCountry: this.state.phoneCountry, - phoneNumber: this.refs.phoneNumber ? this.refs.phoneNumber.value.trim() : '', + phoneNumber: this.state.phoneNumber, }); if (promise) { @@ -143,13 +148,13 @@ module.exports = React.createClass({ }, validateField: function(fieldID, eventType) { - const pwd1 = this.refs.password.value.trim(); - const pwd2 = this.refs.passwordConfirm.value.trim(); + const pwd1 = this.state.password.trim(); + const pwd2 = this.state.passwordConfirm.trim(); const allowEmpty = eventType === "blur"; switch (fieldID) { case FIELD_EMAIL: { - const email = this.refs.email.value; + const email = this.state.email; const emailValid = email === '' || Email.looksValid(email); if (this._authStepIsRequired('m.login.email.identity') && (!emailValid || email === '')) { this.markFieldValid(fieldID, false, "RegistrationForm.ERR_MISSING_EMAIL"); @@ -157,7 +162,7 @@ module.exports = React.createClass({ break; } case FIELD_PHONE_NUMBER: { - const phoneNumber = this.refs.phoneNumber ? this.refs.phoneNumber.value : ''; + const phoneNumber = this.state.phoneNumber; const phoneNumberValid = phoneNumber === '' || phoneNumberLooksValid(phoneNumber); if (this._authStepIsRequired('m.login.msisdn') && (!phoneNumberValid || phoneNumber === '')) { this.markFieldValid(fieldID, false, "RegistrationForm.ERR_MISSING_PHONE_NUMBER"); @@ -165,7 +170,7 @@ module.exports = React.createClass({ break; } case FIELD_USERNAME: { - const username = this.refs.username.value.trim(); + const username = this.state.username; if (allowEmpty && username === '') { this.markFieldValid(fieldID, true); } else if (!SAFE_LOCALPART_REGEX.test(username)) { @@ -230,21 +235,6 @@ module.exports = React.createClass({ this.props.onValidationChange(fieldErrors); }, - fieldElementById(fieldID) { - switch (fieldID) { - case FIELD_EMAIL: - return this.refs.email; - case FIELD_PHONE_NUMBER: - return this.refs.phoneNumber; - case FIELD_USERNAME: - return this.refs.username; - case FIELD_PASSWORD: - return this.refs.password; - case FIELD_PASSWORD_CONFIRM: - return this.refs.passwordConfirm; - } - }, - _classForField: function(fieldID, ...baseClasses) { let cls = baseClasses.join(' '); if (this.state.fieldErrors[fieldID]) { @@ -258,14 +248,32 @@ module.exports = React.createClass({ this.validateField(FIELD_EMAIL, ev.type); }, + onEmailChange(ev) { + this.setState({ + email: ev.target.value, + }); + }, + onPasswordBlur(ev) { this.validateField(FIELD_PASSWORD, ev.type); }, + onPasswordChange(ev) { + this.setState({ + password: ev.target.value, + }); + }, + onPasswordConfirmBlur(ev) { this.validateField(FIELD_PASSWORD_CONFIRM, ev.type); }, + onPasswordConfirmChange(ev) { + this.setState({ + passwordConfirm: ev.target.value, + }); + }, + onPhoneCountryChange(newVal) { this.setState({ phoneCountry: newVal.iso2, @@ -277,10 +285,22 @@ module.exports = React.createClass({ this.validateField(FIELD_PHONE_NUMBER, ev.type); }, + onPhoneNumberChange(ev) { + this.setState({ + phoneNumber: ev.target.value, + }); + }, + onUsernameBlur(ev) { this.validateField(FIELD_USERNAME, ev.type); }, + onUsernameChange(ev) { + this.setState({ + username: ev.target.value, + }); + }, + /** * A step is required if all flows include that step. * @@ -343,12 +363,12 @@ module.exports = React.createClass({ ); } @@ -370,13 +390,13 @@ module.exports = React.createClass({ phoneSection = ; } @@ -395,32 +415,35 @@ module.exports = React.createClass({
diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 84d14802d1..daf6ec0ce1 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -53,12 +53,6 @@ export default class Field extends React.PureComponent { }; } - /* TODO: Remove this once `RegistrationForm` no longer uses refs */ - get value() { - if (!this.refs.fieldInput) return null; - return this.refs.fieldInput.value; - } - onChange = (ev) => { if (this.props.onValidate) { const result = this.props.onValidate(ev.target.value); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 26113d3d4f..d450e92d71 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1293,8 +1293,7 @@ "Find other public servers or use a custom server": "Find other public servers or use a custom server", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", - "Please install Chrome or Firefox for the best experience.": "Please install Chrome or Firefox for the best experience.", - "Safari and Opera work too.": "Safari and Opera work too.", + "Please install Chrome, Firefox, or Safari for the best experience.": "Please install Chrome, Firefox, or Safari for the best experience.", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!", "I understand the risks and wish to continue": "I understand the risks and wish to continue", "Couldn't load page": "Couldn't load page", diff --git a/yarn.lock b/yarn.lock index d1da66b82b..36fa22ae44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4065,10 +4065,10 @@ just-extend@^4.0.2: resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw== -karma-chrome-launcher@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-0.2.3.tgz#4c6d700d163a9d34c618efd87918be49e7a4a8c9" - integrity sha1-TG1wDRY6nTTGGO/YeRi+SeekqMk= +karma-chrome-launcher@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" + integrity sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w== dependencies: fs-access "^1.0.0" which "^1.2.1"