diff --git a/.gitignore b/.gitignore index 90e261de2..1325f56fb 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ ENV /test/integration-cypress/cypress/screenshots /test/integration-cypress/cypress/videos /test/integration-cypress/package-lock.json +/test/integration/node_modules/* diff --git a/.travis.yml b/.travis.yml index a88817457..b4f98bb41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,12 @@ env: - API_HOST_VAR=API_HOST_$TRAVIS_BRANCH - API_HOST=${!API_HOST_VAR} - API_HOST=${API_HOST:-$API_HOST_STAGING} + - ROOT_URL_master=https://scratch.mit.edu + - ROOT_URL_STAGING=https://scratch.ly + - ROOT_URL_VAR=ROOT_URL_$TRAVIS_BRANCH + - ROOT_URL=${!ROOT_URL_VAR} + - ROOT_URL=${ROOT_URL:-$ROOT_URL_STAGING} + - PATH=$PATH:$PWD/test/integration/node_modules/chromedriver/bin # EB_AWS_ACCESS_KEY_ID - secure: A138rYuXDsOmpEwYxZ31WyXEeq5fgr9qyqsQh1nTFsjBKpFtNM+CN9e0QJQFT3PLs4wH/lWTRSyHxakxKQS1sxq828f9gHed+f15REKk/fRUplcCYIexT9xKVtU3D8CRNn/KBFWk75fZyZt20eyOVIv4h3pInKQz7y84J6PWzB1BCrAFvADrzS1X68Z3NJJLyxnz0YEurzz8mC2v4D0s/XifKTWvRtefD4QM6pE0C2iYyk+ThrLwg7i9FDHVfo0MrkgcdX7mz37SnTr7p7mHWnGXrGngi/NiDRQ+Uwwq/sr2UIww0rCwS1xsOcS//dC4NNqrrt1kUTsoC1Yt87Ny+gI0nUplsfEpdKajAkOYdANC5bJUGqPdSlOds1v9aJs9Hx48uGamWkm/3cFmoJ5uA2ZzUwbSGjTkWbnhwzT0YRvcLGhP1WE/EswaIyK5qMp522E79mP1yH6M750iUvi4N39+QW1BNX3ADkOwyAI67ArX5on5gWP83RXcJ15im7XsBpsmVn/KXi6AouWPb8jmSmKCj0QZCzfLY7ivM42IugYpK2NV7kFB38DpXQamJ5eskgwYa3elRmednIFUuwb1QDnONvJogVjk4CLmoSxssC2mJnnrUItM7l8G6As81GMI+6lTtl86hAuXBjUk60FMbgTAQDX9ll26LgpBy8jHSx8= # EB_AWS_SECRET_ACCESS_KEY @@ -58,6 +64,7 @@ env: - NODE_ENV=production - WWW_VERSION=${TRAVIS_COMMIT:0:5} addons: + chrome: stable apt: sources: - ubuntu-toolchain-r-test @@ -66,20 +73,33 @@ addons: install: - sudo -H pip install -r requirements.txt - npm --production=false install -deploy: -- provider: script - skip_cleanup: $SKIP_CLEANUP - script: env make sync - on: - repo: LLK/scratch-www - branch: - - develop - - hotfix/* - - release/* -- provider: script - skip_cleanup: $SKIP_CLEANUP - script: env make sync - on: - repo: LLK/scratch-www - branch: - - master +jobs: + include: + - stage: test + deploy: + - provider: script + skip_cleanup: $SKIP_CLEANUP + script: env make sync + on: + repo: LLK/scratch-www + branch: + - develop + - hotfix/* + - release/* + - provider: script + skip_cleanup: $SKIP_CLEANUP + script: env make sync + on: + repo: LLK/scratch-www + branch: + - master + - stage: smoke + install: + - cd test/integration + - npm install + - cd - + script: npm run smoke +stages: +- test +- name: smoke + if: branch IN (travis) and type != pull_request diff --git a/Makefile b/Makefile index cb2c10c9e..6fed25bde 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,9 @@ integration: smoke: $(TAP) ./test/integration/smoke-testing/*.js --timeout=3600 + +smoke-verbose: + $(TAP) ./test/integration/smoke-testing/*.js --timeout=3600 -R spec localization: $(TAP) ./test/localization/*.js diff --git a/package.json b/package.json index fec54dc38..951a6e528 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "stop": "make stop", "test": "make test", "smoke": "make smoke", + "smoke-verbose": "make smoke-verbose", "watch": "make watch", "build": "make build", "dev": "make watch && make start &" @@ -28,10 +29,12 @@ "express-http-proxy": "1.1.0", "lodash.defaults": "4.0.1", "newrelic": "1.25.4", - "raven": "0.10.0" + "raven": "0.10.0", + "scratch-gui": "0.1.0-prerelease.20180529181946" }, "devDependencies": { "ajv": "6.4.0", + "approximate-number": "2.0.0", "async": "1.5.2", "autoprefixer": "6.3.6", "babel-cli": "6.26.0", @@ -94,7 +97,6 @@ "redux-thunk": "2.0.1", "sass-lint": "1.5.1", "sass-loader": "6.0.6", - "scratch-gui": "0.1.0-prerelease.20180427201459", "scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master", "slick-carousel": "1.6.0", "source-map-support": "0.3.2", diff --git a/src/_colors.scss b/src/_colors.scss index f1fcf7fa5..2e7bd838b 100644 --- a/src/_colors.scss +++ b/src/_colors.scss @@ -18,9 +18,11 @@ $ui-border: hsla(0, 0, 85, 1); //#D9D9D9 /* 3.0 colors */ /* Using www naming convention for now, should be consistent with gui */ -$ui-green: hsla(163, 83, 40, 1); //#0fbd8c Pen Primary -$ui-coral: hsla(350, 100, 70, 1); //#FF6680 More Priamry +$ui-green: hsla(163, 83, 40, 1); // #0fbd8c Pen Primary +$ui-coral: hsla(350, 100, 70, 1); // #FF6680 More Primary +$ui-coral-dark: hsla(350, 100, 60, 1); // #FF3355 More tertiary $ui-blue-10percent: hsla(215, 100, 65, .1); +$ui-blue-25percent: hsla(215, 100, 65, .25); $ui-orange-25percent: hsla(35, 90, 55, .25); /* Overlay UI Gray Colors */ diff --git a/src/components/forms/inplace-input.scss b/src/components/forms/inplace-input.scss index 46deab4b9..33bc254b3 100644 --- a/src/components/forms/inplace-input.scss +++ b/src/components/forms/inplace-input.scss @@ -3,16 +3,18 @@ .inplace-input { transition: all .5s ease; - border: 2px dashed $ui-dark-gray; - border-radius: 5px; + border: 2px dashed $ui-blue-25percent; + border-radius: 8px; background-color: transparent; padding: 0 1rem; + width: calc(100% - 2.25rem); color: $type-gray; &:focus { transition: all .5s ease; outline: none; - border: 1px solid $ui-blue; + border: 2px solid $ui-blue; + box-shadow: 0 0 0 4px $ui-blue-25percent; } &.fail { @@ -27,31 +29,41 @@ &::-ms-reveal, &::-ms-clear { display: none; } + + &::placeholder { + font-style: italic; + } } .inplace-textarea { transition: all 1s ease; - margin-bottom: .75rem; - border: 2px dashed $ui-dark-gray; - border-radius: 5px; + border: 2px dashed $ui-blue-25percent; + border-radius: 8px; background-color: $ui-light-gray; padding: .75rem 1rem; - width: calc(100% - 2.25rem); - min-height: 20rem; + width: 100%; line-height: 1.75em; color: $type-gray; - font-size: .875rem; + font-size: 1rem; + box-sizing: border-box; resize: none; &:focus { transition: all 1s ease; outline: none; - border: 1px solid $ui-blue; + border: 2px solid $ui-blue; + box-shadow: 0 0 0 4px $ui-blue-25percent; } &.fail { border: 1px solid $ui-orange; } + + &::placeholder { + padding-top: 1rem; + text-align: center; + font-style: italic; + } } diff --git a/src/components/forms/textarea.scss b/src/components/forms/textarea.scss index d1782d37f..69556f361 100644 --- a/src/components/forms/textarea.scss +++ b/src/components/forms/textarea.scss @@ -22,4 +22,8 @@ &.fail { border: 1px solid $ui-orange; } + + &::placeholder { + font-style: italic; + } } diff --git a/src/components/modal/report/modal.jsx b/src/components/modal/report/modal.jsx new file mode 100644 index 000000000..c6419d4f5 --- /dev/null +++ b/src/components/modal/report/modal.jsx @@ -0,0 +1,186 @@ +const bindAll = require('lodash.bindall'); +const PropTypes = require('prop-types'); +const React = require('react'); +const FormattedMessage = require('react-intl').FormattedMessage; +const injectIntl = require('react-intl').injectIntl; +const intlShape = require('react-intl').intlShape; +const Modal = require('../base/modal.jsx'); +const log = require('../../../lib/log.js'); + +const Form = require('../../forms/form.jsx'); +const Button = require('../../forms/button.jsx'); +const Select = require('../../forms/select.jsx'); +const Spinner = require('../../spinner/spinner.jsx'); +const TextArea = require('../../forms/textarea.jsx'); + +require('../../forms/button.scss'); +require('./modal.scss'); + +class ReportModal extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleReasonSelect', + 'handleSubmit' + ]); + this.state = { + prompt: props.intl.formatMessage({id: 'report.promptPlaceholder'}), + reason: '', + waiting: false + }; + } + handleReasonSelect (name, value) { + const prompts = [ + this.props.intl.formatMessage({id: 'report.promptCopy'}), + this.props.intl.formatMessage({id: 'report.promptUncredited'}), + this.props.intl.formatMessage({id: 'report.promptScary'}), + this.props.intl.formatMessage({id: 'report.promptLanguage'}), + this.props.intl.formatMessage({id: 'report.promptMusic'}), + this.props.intl.formatMessage({id: 'report.promptPersonal'}), + this.props.intl.formatMessage({id: 'report.promptGuidelines'}), + 'not used', + this.props.intl.formatMessage({id: 'report.promptImage'}) + ]; + this.setState({prompt: prompts[value], reason: value}); + } + handleSubmit (formData) { + this.setState({waiting: true}); + this.props.onReport(formData, err => { + if (err) log.error(err); + this.setState({ + prompt: this.props.intl.formatMessage({id: 'report.promptPlaceholder'}), + reason: '', + waiting: false + }); + }); + } + render () { + const { + intl, + onReport, // eslint-disable-line no-unused-vars + type, + ...modalProps + } = this.props; + const contentLabel = intl.formatMessage({id: `report.${type}`}); + return ( + +
+
+
+ {contentLabel} +
+
+ +
+ + + + ) + }} + /> +
+