Compare commits

..

8 Commits

Author SHA1 Message Date
Danny Coates
c97abb46ed bump version 2017-09-26 10:29:26 -07:00
Danny Coates
b8f5e371c7 updated deps 2017-09-26 10:23:30 -07:00
Danny Coates
401311a05f updated deps. removed choo-log 2017-09-20 13:09:33 -07:00
Sahithi
652b8e4e15 Pontoon: Update Telugu (te) localization of Test Pilot: Firefox Send
Localization authors:
- Sahithi <sahithi.thinker@gmail.com>
2017-09-19 11:31:21 +00:00
Merike Sell
99b7e7c0f1 Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Merike Sell <merikes@gmail.com>
2017-09-16 12:52:29 +00:00
Danny Coates
81442bb6f2 set default server states for fira and fileInfo 2017-09-14 12:15:08 -07:00
Danny Coates
137f474b69 fixed A/B test control group selection 2017-09-14 10:02:47 -07:00
Danny Coates
8e14d3f8f7 QA bug fixes 2017-09-13 12:01:55 -07:00
16 changed files with 1361 additions and 775 deletions

2
.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
dist
assets/*.js

View File

@@ -22,7 +22,7 @@ const experiments = {
return this.luckyNumber(state) >= 0.5; return this.luckyNumber(state) >= 0.5;
}, },
variant: function(state) { variant: function(state) {
return this.luckyNumber(state) < 0.5 ? 0 : 1; return this.luckyNumber(state) < 0.75 ? 0 : 1;
}, },
luckyNumber: function(state) { luckyNumber: function(state) {
return luckyNumber( return luckyNumber(
@@ -51,7 +51,7 @@ export default function initialize(state, emitter) {
emitter.on('DOMContentLoaded', () => { emitter.on('DOMContentLoaded', () => {
const xp = experiments[state.query.x]; const xp = experiments[state.query.x];
if (xp) { if (xp) {
xp.run(state.query.v, state, emitter); xp.run(+state.query.v, state, emitter);
} }
}); });

View File

@@ -1,7 +1,7 @@
/* global EXPIRE_SECONDS */ /* global EXPIRE_SECONDS */
import FileSender from './fileSender'; import FileSender from './fileSender';
import FileReceiver from './fileReceiver'; import FileReceiver from './fileReceiver';
import { copyToClipboard, delay, fadeOut } from './utils'; import { copyToClipboard, delay, fadeOut, percent } from './utils';
import * as metrics from './metrics'; import * as metrics from './metrics';
function saveFile(file) { function saveFile(file) {
@@ -54,6 +54,7 @@ function exists(id) {
export default function(state, emitter) { export default function(state, emitter) {
let lastRender = 0; let lastRender = 0;
let updateTitle = false;
function render() { function render() {
emitter.emit('render'); emitter.emit('render');
@@ -74,7 +75,21 @@ export default function(state, emitter) {
} }
} }
emitter.on('DOMContentLoaded', checkFiles); function updateProgress() {
if (updateTitle) {
emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
}
render();
}
emitter.on('DOMContentLoaded', () => {
document.addEventListener('blur', () => (updateTitle = true));
document.addEventListener('focus', () => {
updateTitle = false;
emitter.emit('DOMTitleChange', 'Firefox Send');
});
checkFiles();
});
emitter.on('navigate', checkFiles); emitter.on('navigate', checkFiles);
@@ -107,7 +122,7 @@ export default function(state, emitter) {
emitter.on('upload', async ({ file, type }) => { emitter.on('upload', async ({ file, type }) => {
const size = file.size; const size = file.size;
const sender = new FileSender(file); const sender = new FileSender(file);
sender.on('progress', render); sender.on('progress', updateProgress);
sender.on('encrypting', render); sender.on('encrypting', render);
state.transfer = sender; state.transfer = sender;
render(); render();
@@ -153,7 +168,7 @@ export default function(state, emitter) {
const size = file.size; const size = file.size;
const url = `/api/download/${file.id}`; const url = `/api/download/${file.id}`;
const receiver = new FileReceiver(url, file.key); const receiver = new FileReceiver(url, file.key);
receiver.on('progress', render); receiver.on('progress', updateProgress);
receiver.on('decrypting', render); receiver.on('decrypting', render);
state.transfer = receiver; state.transfer = receiver;
const links = openLinksInNewTab(); const links = openLinksInNewTab();

View File

@@ -1,5 +1,4 @@
import app from './routes'; import app from './routes';
import log from 'choo-log';
import locale from '../common/locales'; import locale from '../common/locales';
import fileManager from './fileManager'; import fileManager from './fileManager';
import dragManager from './dragManager'; import dragManager from './dragManager';
@@ -14,8 +13,6 @@ if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install(); Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
} }
app.use(log());
app.use((state, emitter) => { app.use((state, emitter) => {
// init state // init state
state.transfer = null; state.transfer = null;
@@ -28,6 +25,13 @@ app.use((state, emitter) => {
uploadButtonStyle: 'browse btn' uploadButtonStyle: 'browse btn'
}; };
emitter.on('DOMContentLoaded', async () => { emitter.on('DOMContentLoaded', async () => {
if (
/firefox/i.test(navigator.userAgent) &&
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) <=
49
) {
return emitter.emit('replaceState', '/unsupported/outdated');
}
const ok = await canHasSend(assets.get('cryptofill.js')); const ok = await canHasSend(assets.get('cryptofill.js'));
if (!ok) { if (!ok) {
const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm'; const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';

View File

@@ -4,7 +4,7 @@ const assets = require('../../common/assets');
function timeLeft(milliseconds) { function timeLeft(milliseconds) {
const minutes = Math.floor(milliseconds / 1000 / 60); const minutes = Math.floor(milliseconds / 1000 / 60);
const hours = Math.floor(minutes / 60); const hours = Math.floor(minutes / 60);
const seconds = Math.floor(milliseconds / 1000 % 60); const seconds = Math.floor((milliseconds / 1000) % 60);
if (hours >= 1) { if (hours >= 1) {
return `${hours}h ${minutes % 60}m`; return `${hours}h ${minutes % 60}m`;
} else if (hours === 0) { } else if (hours === 0) {

View File

@@ -40,11 +40,16 @@ module.exports = function(state, emit) {
state.translate('downloadFileSize', { size })}</span> state.translate('downloadFileSize', { size })}</span>
</div> </div>
<div class="description">${state.translate('downloadMessage')}</div> <div class="description">${state.translate('downloadMessage')}</div>
<img src="${assets.get( <img
'illustration_download.svg' src="${assets.get('illustration_download.svg')}"
)}" id="download-img" alt="${state.translate('downloadAltText')}"/> id="download-img"
alt="${state.translate('downloadAltText')}"/>
<div> <div>
<button id="download-btn" class="btn" onclick=${download}>${state.translate( <button
id="download-btn"
class="btn"
title="${state.translate('downloadButtonLabel')}"
onclick=${download}>${state.translate(
'downloadButtonLabel' 'downloadButtonLabel'
)}</button> )}</button>
</div> </div>

View File

@@ -17,13 +17,13 @@ module.exports = function(state, emit) {
})}</div> })}</div>
<div id="copy"> <div id="copy">
<input id="link" type="url" value="${file.url}" readonly="true"/> <input id="link" type="url" value="${file.url}" readonly="true"/>
<button id="copy-btn" class="btn" onclick=${copyLink}>${state.translate( <button id="copy-btn" class="btn" title="${state.translate(
'copyUrlFormButton' 'copyUrlFormButton'
)}</button> )}" onclick=${copyLink}>${state.translate('copyUrlFormButton')}</button>
</div> </div>
<button id="delete-file" class="btn" onclick=${deleteFile}>${state.translate( <button id="delete-file" class="btn" title="${state.translate(
'deleteFileButton' 'deleteFileButton'
)}</button> )}" onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate( <a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
'sendAnotherFileLink' 'sendAnotherFileLink'
)}</a> )}</a>

View File

@@ -21,9 +21,9 @@ module.exports = function(state, emit) {
transfer.msg, transfer.msg,
transfer.sizes transfer.sizes
)}</div> )}</div>
<button id="cancel-upload" onclick=${cancel}>${state.translate( <button id="cancel-upload" title="${state.translate(
'uploadingPageCancel' 'uploadingPageCancel'
)}</button> )}" onclick=${cancel}>${state.translate('uploadingPageCancel')}</button>
</div> </div>
</div> </div>
`; `;

View File

@@ -24,9 +24,9 @@ module.exports = function(state, emit) {
)}</em></span> )}</em></span>
<form method="post" action="upload" enctype="multipart/form-data"> <form method="post" action="upload" enctype="multipart/form-data">
<label for="file-upload" id="browse" class="${state.config <label for="file-upload" id="browse" class="${state.config
.uploadButtonStyle}">${state.translate( .uploadButtonStyle}" title="${state.translate(
'uploadPageBrowseButton1' 'uploadPageBrowseButton1'
)}</label> )}">${state.translate('uploadPageBrowseButton1')}</label>
<input id="file-upload" type="file" name="fileUploaded" onchange=${upload} /> <input id="file-upload" type="file" name="fileUploaded" onchange=${upload} />
</form> </form>
</div> </div>

View File

@@ -278,7 +278,7 @@ a {
font-size: 20px; font-size: 20px;
} }
input[type="file"] { input[type='file'] {
display: none; display: none;
} }
@@ -359,7 +359,7 @@ tbody {
cursor: pointer; cursor: pointer;
} }
.icon-copy[disabled="disabled"] { .icon-copy[disabled='disabled'] {
pointer-events: none; pointer-events: none;
opacity: 0.3; opacity: 0.3;
} }
@@ -398,7 +398,7 @@ tbody {
/* Popup arrow */ /* Popup arrow */
.popup .popuptext::after { .popup .popuptext::after {
content: ""; content: '';
position: absolute; position: absolute;
bottom: -11px; bottom: -11px;
left: 20px; left: 20px;

1967
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "firefox-send", "name": "firefox-send",
"description": "File Sharing Experiment", "description": "File Sharing Experiment",
"version": "1.2.0", "version": "1.2.3",
"author": "Mozilla (https://mozilla.org)", "author": "Mozilla (https://mozilla.org)",
"repository": "mozilla/send", "repository": "mozilla/send",
"homepage": "https://github.com/mozilla/send/", "homepage": "https://github.com/mozilla/send/",
@@ -17,7 +17,7 @@
"lint-locales": "node scripts/lint-locales", "lint-locales": "node scripts/lint-locales",
"lint-locales:dev": "npm run lint-locales", "lint-locales:dev": "npm run lint-locales",
"lint-locales:prod": "npm run lint-locales -- --production", "lint-locales:prod": "npm run lint-locales -- --production",
"format": "prettier '!(dist|node_modules|assets)/**/*.js' 'assets/*.css' --single-quote --write", "format": "prettier '**/*.js' 'assets/*.css' --single-quote --write",
"get-prod-locales": "node scripts/get-prod-locales", "get-prod-locales": "node scripts/get-prod-locales",
"get-prod-locales:write": "npm run get-prod-locales -- --write", "get-prod-locales:write": "npm run get-prod-locales -- --write",
"changelog": "github-changes -o mozilla -r send --only-pulls --use-commit-body --no-merges", "changelog": "github-changes -o mozilla -r send --only-pulls --use-commit-body --no-merges",
@@ -43,7 +43,7 @@
"node": ">=8.2.0" "node": ">=8.2.0"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^7.1.2", "autoprefixer": "^7.1.4",
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-loader": "^7.1.2", "babel-loader": "^7.1.2",
"babel-plugin-yo-yoify": "^0.7.0", "babel-plugin-yo-yoify": "^0.7.0",
@@ -51,13 +51,12 @@
"babel-preset-env": "^1.6.0", "babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1", "babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1", "babel-preset-stage-2": "^6.24.1",
"choo-log": "^7.2.1",
"copy-webpack-plugin": "^4.0.1", "copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5", "cross-env": "^5.0.5",
"css-loader": "^0.28.5", "css-loader": "^0.28.7",
"css-mqpacker": "^6.0.1", "css-mqpacker": "^6.0.1",
"cssnano": "^3.10.0", "cssnano": "^3.10.0",
"eslint": "^4.5.0", "eslint": "^4.7.2",
"eslint-plugin-mocha": "^4.11.0", "eslint-plugin-mocha": "^4.11.0",
"eslint-plugin-node": "^5.1.1", "eslint-plugin-node": "^5.1.1",
"eslint-plugin-security": "^1.4.0", "eslint-plugin-security": "^1.4.0",
@@ -68,37 +67,37 @@
"github-changes": "^1.1.0", "github-changes": "^1.1.0",
"html-loader": "^0.5.1", "html-loader": "^0.5.1",
"husky": "^0.14.3", "husky": "^0.14.3",
"lint-staged": "^4.0.4", "lint-staged": "^4.2.3",
"mocha": "^3.5.0", "mocha": "^3.5.3",
"nanobus": "^4.2.0", "nanobus": "^4.2.0",
"npm-run-all": "^4.0.2", "npm-run-all": "^4.1.1",
"postcss-loader": "^2.0.6", "postcss-loader": "^2.0.6",
"prettier": "^1.5.3", "prettier": "^1.7.0",
"proxyquire": "^1.8.0", "proxyquire": "^1.8.0",
"raven-js": "^3.17.0", "raven-js": "^3.17.0",
"redis-mock": "^0.20.0", "redis-mock": "^0.20.0",
"require-from-string": "^1.2.1", "require-from-string": "^1.2.1",
"rimraf": "^2.6.1", "rimraf": "^2.6.2",
"selenium-webdriver": "^3.5.0", "selenium-webdriver": "^3.5.0",
"sinon": "^3.2.1", "sinon": "^3.3.0",
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
"stylelint-config-standard": "^17.0.0", "stylelint-config-standard": "^17.0.0",
"stylelint-no-unsupported-browser-features": "^1.0.0", "stylelint-no-unsupported-browser-features": "^1.0.0",
"supertest": "^3.0.0", "supertest": "^3.0.0",
"testpilot-ga": "^0.3.0", "testpilot-ga": "^0.3.0",
"val-loader": "^1.0.2", "val-loader": "^1.0.2",
"webpack": "^3.5.5", "webpack": "^3.6.0",
"webpack-dev-server": "^2.7.1", "webpack-dev-server": "^2.8.2",
"webpack-manifest-plugin": "^1.3.1", "webpack-manifest-plugin": "^1.3.2",
"webpack-unassert-loader": "^1.2.0" "webpack-unassert-loader": "^1.2.0"
}, },
"dependencies": { "dependencies": {
"aws-sdk": "^2.103.0", "aws-sdk": "^2.122.0",
"body-parser": "^1.17.2", "body-parser": "^1.18.2",
"choo": "^6.0.0", "choo": "^6.1.0",
"connect-busboy": "0.0.2", "connect-busboy": "0.0.2",
"convict": "^4.0.0", "convict": "^4.0.0",
"express": "^4.15.4", "express": "^4.15.5",
"express-request-language": "^1.1.12", "express-request-language": "^1.1.12",
"fluent": "^0.4.1", "fluent": "^0.4.1",
"fluent-langneg": "^0.1.0", "fluent-langneg": "^0.1.0",
@@ -123,6 +122,7 @@
"es-CL", "es-CL",
"es-ES", "es-ES",
"es-MX", "es-MX",
"et",
"fa", "fa",
"fr", "fr",
"fy-NL", "fy-NL",

View File

@@ -21,6 +21,7 @@ uploadingPageMessage = Aegumise sätteid saab muuta siis, kui faili üles laadit
uploadingPageCancel = Katkesta üleslaadimine uploadingPageCancel = Katkesta üleslaadimine
uploadCancelNotification = Üleslaadimine katkestati uploadCancelNotification = Üleslaadimine katkestati
uploadingPageLargeFileMessage = Fail on suur ja selle üleslaadimine võib aega võtta. uploadingPageLargeFileMessage = Fail on suur ja selle üleslaadimine võib aega võtta.
uploadingFileNotification = Teavita mind üleslaadimise lõppemisest.
uploadSuccessConfirmHeader = Saatmiseks valmis uploadSuccessConfirmHeader = Saatmiseks valmis
uploadSvgAlt = Laadi üles uploadSvgAlt = Laadi üles
uploadSuccessTimingHeader = Link failile aegub pärast 1. allalaadimist või 24 tunni möödumisel. uploadSuccessTimingHeader = Link failile aegub pärast 1. allalaadimist või 24 tunni möödumisel.
@@ -64,6 +65,7 @@ copyFileList = Kopeeri URL
// expiryFileList is used as a column header // expiryFileList is used as a column header
expiryFileList = Aegub expiryFileList = Aegub
deleteFileList = Kustuta deleteFileList = Kustuta
nevermindButton = Ära pane tähele
legalHeader = Tingimused ja privaatsusreeglid legalHeader = Tingimused ja privaatsusreeglid
legalNoticeTestPilot = Firefox Send on praegu Test Piloti eksperiment ja sellele rakenduvad Test Piloti <a>teenusetingimused</a> ning <a>privaatsusreeglid</a>. Rohkem teavet selle eksperimendi ja kogutavate andmete kohta leiab <a>siit</a>. legalNoticeTestPilot = Firefox Send on praegu Test Piloti eksperiment ja sellele rakenduvad Test Piloti <a>teenusetingimused</a> ning <a>privaatsusreeglid</a>. Rohkem teavet selle eksperimendi ja kogutavate andmete kohta leiab <a>siit</a>.
legalNoticeMozilla = Firefox Sendi veebilehe kasutamisele rakenduvad ka Mozilla <a>veebilehtede privaatsusreeglid</a> ja <a>veebilehtede teenusetingimused</a>. legalNoticeMozilla = Firefox Sendi veebilehe kasutamisele rakenduvad ka Mozilla <a>veebilehtede privaatsusreeglid</a> ja <a>veebilehtede teenusetingimused</a>.

View File

@@ -48,6 +48,7 @@ linkExpiredAlt = లంకె గడువు ముగిసింది
expiredPageHeader = ఈ లంకె గడువు ముగిసింది లేదా ముందు ఎప్పుడూ ఉనికిలో లేదు! expiredPageHeader = ఈ లంకె గడువు ముగిసింది లేదా ముందు ఎప్పుడూ ఉనికిలో లేదు!
notSupportedHeader = మీ విహారిణికి మద్దతు లేదు. notSupportedHeader = మీ విహారిణికి మద్దతు లేదు.
notSupportedLink = నా విహారిణికి ఎందుకు మద్దతు లేదు? notSupportedLink = నా విహారిణికి ఎందుకు మద్దతు లేదు?
notSupportedOutdatedDetail = దురదృష్టవశాత్తు Firefox యొక్క ఈ వెర్షన్ Firefox సాంకేతికతను పంపే వెబ్ సాంకేతికతకు మద్దతు ఇవ్వదు. మీరు మీ బ్రౌజర్ని నవీకరించాలి.
updateFirefox = Firefoxను నవీకరించు updateFirefox = Firefoxను నవీకరించు
downloadFirefoxButtonSub = ఉచిత దిగుమతులు downloadFirefoxButtonSub = ఉచిత దిగుమతులు
uploadedFile = దస్త్రం uploadedFile = దస్త్రం

View File

@@ -19,6 +19,8 @@ module.exports = function(req) {
uploadWindowStyle: 'upload-window', uploadWindowStyle: 'upload-window',
uploadButtonStyle: 'browse btn' uploadButtonStyle: 'browse btn'
}, },
fira: false,
fileInfo: {},
layout layout
}; };
}; };

View File

@@ -54,7 +54,9 @@ describe('Server integration tests', function() {
} }
it('Responds with a 200 when the service is up', function() { it('Responds with a 200 when the service is up', function() {
return request(server).get('/').expect(200); return request(server)
.get('/')
.expect(200);
}); });
it('Rejects with a 404 when a file id is not valid', function() { it('Rejects with a 404 when a file id is not valid', function() {
@@ -89,7 +91,9 @@ describe('Server integration tests', function() {
}); });
it('Responds with a 200 if a file exists', function() { it('Responds with a 200 if a file exists', function() {
return request(server).get('/exists/' + fileId).expect(200); return request(server)
.get('/exists/' + fileId)
.expect(200);
}); });
it('Exists in the redis server', function() { it('Exists in the redis server', function() {
@@ -107,7 +111,9 @@ describe('Server integration tests', function() {
}); });
it('Fails delete if the id is invalid', function() { it('Fails delete if the id is invalid', function() {
return request(server).post('/delete/1').expect(404); return request(server)
.post('/delete/1')
.expect(404);
}); });
it('Successfully deletes if the id is valid and the delete token matches', function( it('Successfully deletes if the id is valid and the delete token matches', function(
@@ -129,7 +135,9 @@ describe('Server integration tests', function() {
}); });
it('Responds with a 404 if a file does not exist', function() { it('Responds with a 404 if a file does not exist', function() {
return request(server).get('/exists/notfound').expect(404); return request(server)
.get('/exists/notfound')
.expect(404);
}); });
it('Uploads properly after a delete', function(done) { it('Uploads properly after a delete', function(done) {
@@ -150,21 +158,25 @@ describe('Server integration tests', function() {
}); });
it('Responds with a 200 for the download page', function() { it('Responds with a 200 for the download page', function() {
return request(server).get('/download/' + fileId).expect(200); return request(server)
.get('/download/' + fileId)
.expect(200);
}); });
it('Downloads a file properly', function() { it('Downloads a file properly', function() {
return request(server).get('/assets/download/' + fileId).then(res => { return request(server)
assert(res.header.hasOwnProperty('content-disposition')); .get('/assets/download/' + fileId)
assert(res.header.hasOwnProperty('content-type')); .then(res => {
assert(res.header.hasOwnProperty('content-length')); assert(res.header.hasOwnProperty('content-disposition'));
assert(res.header.hasOwnProperty('x-file-metadata')); assert(res.header.hasOwnProperty('content-type'));
assert.equal( assert(res.header.hasOwnProperty('content-length'));
res.header['content-disposition'], assert(res.header.hasOwnProperty('x-file-metadata'));
'attachment; filename=test_upload.txt' assert.equal(
); res.header['content-disposition'],
assert.equal(res.header['content-type'], 'application/octet-stream'); 'attachment; filename=test_upload.txt'
}); );
assert.equal(res.header['content-type'], 'application/octet-stream');
});
}); });
it('The file is deleted after one download', function() { it('The file is deleted after one download', function() {