Skip to content

Commit

Permalink
Merge branch 'master' into v2.35.0
Browse files Browse the repository at this point in the history
  • Loading branch information
gniezen authored Mar 11, 2021
2 parents 844fafc + 33eb510 commit e662775
Show file tree
Hide file tree
Showing 108 changed files with 3,182 additions and 3,779 deletions.
7 changes: 5 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
// I want to use babel-eslint for parsing!
"parser": "babel-eslint",
"parser": "@babel/eslint-parser",
"env": {
// I write for browser
"browser": true,
Expand All @@ -9,6 +9,7 @@
"es6": true
},
"globals": {
"jest": true,
"chai": false,
"console": false,
"define": false,
Expand Down Expand Up @@ -52,10 +53,12 @@
"no-buffer-constructor": "warn"
},
"plugins": [
"@babel",
"react",
"promise",
"import",
"lodash"
"lodash",
"jest"
],
"settings": {
"import/resolver": {
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ENV NODE_VERSION "v12.13.0"

# Lots of packages. Some dependencies and stuff for GUI.
RUN apt-get -qq -y update && \
apt-get -qq -y install build-essential git curl libusb-1.0 libavutil-dev \
apt-get -qq -y install build-essential git curl libusb-1.0 libavutil-dev libxss1 \
libsecret-1-dev libudev-dev libgtk-3-0 libcanberra-gtk3-module packagekit-gtk3-module \
chromium-browser

Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This README is focused on just the details of getting the uploader running local
- [Linting & Code Style](#linting--code-style)
- [Docs](#docs)
- [Publishing](#publishing)
- [Use of LGPL libraries](#use-of-lgpl-libraries)

* * * * *

Expand Down Expand Up @@ -255,3 +256,40 @@ This project uses a [two package.json structure](https://github.com/electron-use
1. If the module is native to a platform or otherwise should be included with the published package (i.e. bcrypt, openbci), it should be listed under `dependencies` in `./app/package.json`.
2. If a module is `import`ed by another module, include it in `dependencies` in `./package.json`. See [this ESLint rule](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md).
3. Otherwise, modules used for building, testing and debugging should be included in `devDependencies` in `./package.json`.

## Use of LGPL libraries

Tidepool Uploader makes use of the following LGPL-licensed libraries:

- libmtp (http://libmtp.sourceforge.net/)
- LZO implementation in libavutil, which is part of FFmpeg (https://github.com/FFmpeg/FFmpeg/tree/master/libavutil)

These libraries are used in the following Node.js modules created by Tidepool and are dependencies of the Tidepool Uploader:

- https://github.com/tidepool-org/node-mtp (libmtp)
- https://github.com/tidepool-org/lzo-decompress (libavutil)

The LGPL is intended to allow use of libraries in applications that don’t necessarily distribute the source of the application. The LGPL has two requirements:

- users must have access to the source code of the library
- users can make use of modified versions of the library

To satisfy (1) we provide links to the relevant code repositories. To satisfy (2) we dynamically link to the library, so that it’s possible to swap it out for another version of the library.

### Impact on Tidepool

Compile FFmpeg ourselves to ensure that we’re using the LGPL version and only include the minimal set of libraries
Use dynamic linking (e.g. on Windows this means using a .dll, and on MacOS a .dylib) when linking to these libraries
Mention that the software uses libraries from the FFmpeg project and libmtp under the LGPLv3, e.g. `This software uses code of <a href=http://ffmpeg.org>FFmpeg</a> and <a href=”http://libmtp.sourceforge.net/”>libmtp</a> licensed under the <a href=a href=https://www.gnu.org/licenses/lgpl.html>LGPLv3</a> and its source can be downloaded <a href=”https://github.com/FFmpeg/FFmpeg/tree/master/libavutil”>here</a> and <a href=”https://sourceforge.net/projects/libmtp/”>here</a>`


### Impact on 3rd parties

If your EULA claims ownership over the code, you have to explicitly mention that you do not own FFmpeg or libmtp, and where the relevant owners can be found.


### References

- [LGPL v3 License Text](https://www.gnu.org/licenses/lgpl.html) (on gnu.org)
- [LGPL on Wikipedia](https://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License)

11 changes: 11 additions & 0 deletions __mocks__/electron.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const electron = jest.genMockFromModule('electron');

function getGlobal(string) {
if (string === 'i18n') {
return { t: (string) => string };
}
}

electron.remote = { getGlobal };

module.exports = electron;
11 changes: 7 additions & 4 deletions app/components/AdHocModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import styles from '../../styles/components/AdHocModal.module.less';
import step1_img from '../../images/adhoc_s1.png';
import step2_img from '../../images/adhoc_s2.png';

import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

export class AdHocModal extends Component {
handleContinue = () => {
const { showingAdHocPairingDialog, sync } = this.props;
Expand All @@ -44,25 +47,25 @@ export class AdHocModal extends Component {
<div className={styles.modalWrap}>
<div className={styles.modal}>
<div className={styles.title}>
<div>{'Allow the connection on the pump:'}</div>
<div>{i18n.t('Allow the connection on the pump:')}</div>
</div>
<hr className={styles.hr} />
<div className={styles.text}>
<div className={styles.body}>
<div className={styles.step}>
<div><span className={styles.numeral}>1.</span> Scroll down</div>
<div><span className={styles.numeral}>1.</span> {i18n.t('Scroll down')}</div>
<div><img className={styles.image} src={step1_img} /></div>
</div>
<div className={styles.step}>
<div><span className={styles.numeral}>2.</span> Select "Yes"</div>
<div><span className={styles.numeral}>2.</span> {i18n.t('Select \"Yes\"')}</div>
<div><img className={styles.image} src={step2_img} /></div>
</div>
</div>
</div>
<hr className={styles.hr} />
<div className={styles.actions}>
<button className={styles.buttonSecondary} onClick={this.handleContinue}>
Continue
{i18n.t('Continue')}
</button>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion app/components/ClinicUploadDone.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ var PropTypes = require('prop-types');

var styles = require('../../styles/components/ClinicUploadDone.module.less');

import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

class ClinicUploadDone extends React.Component {
static propTypes = {
onClicked: PropTypes.func.isRequired,
Expand All @@ -42,7 +45,7 @@ class ClinicUploadDone extends React.Component {
<a className={styles.button}
onClick={this.handleClick}
disabled={!this.hasCompletedUpload()} >
Done
{i18n.t('Done')}
</a>
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion app/components/ClinicUserBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ var sundial = require('sundial');
var personUtils = require('../../lib/core/personUtils');
var cx = require('classnames');

import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

var styles = require('../../styles/components/ClinicUserBlock.module.less');

class ClinicUserBlock extends React.Component {
Expand Down Expand Up @@ -61,7 +64,7 @@ class ClinicUserBlock extends React.Component {
</div>
{isCustodialAccount &&
<div className={editClasses} onClick={isUploadInProgress ? this.noopHandler : this.props.onEditUser}>
Edit Info
{i18n.t('Edit Info')}
</div>
}
</div>
Expand Down
57 changes: 30 additions & 27 deletions app/components/ClinicUserEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,24 @@ var sundial = require('sundial');
var personUtils = require('../../lib/core/personUtils');
var styles = require('../../styles/components/ClinicUserEdit.module.less');

import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

function zeroPad(value){
return _.padStart(value, 2, '0');
}

function validateForm(values){
var errors = {};
if(!values.fullName){
errors.fullName = 'Your patient\'s full name is needed';
errors.fullName = i18n.t('Your patient\'s full name is needed');
}
if(values.year && values.month && values.day){
if(!isValidDate(values.year + '-' + values.month + '-' + zeroPad(values.day))){
errors.year = 'Hmm, this date doesn’t look right';
errors.year = i18n.t('Hmm, this date doesn’t look right');
}
} else {
errors.year = 'Hmm, this date doesn’t look right';
errors.year = i18n.t('Hmm, this date doesn’t look right');
}
return errors;
}
Expand All @@ -51,19 +54,19 @@ function isValidDate(dateString){
}

var MONTHS = [
{value: '', label: 'Month'},
{value: '01', label: 'January'},
{value: '02', label: 'February'},
{value: '03', label: 'March'},
{value: '04', label: 'April'},
{value: '05', label: 'May'},
{value: '06', label: 'June'},
{value: '07', label: 'July'},
{value: '08', label: 'August'},
{value: '09', label: 'September'},
{value: '10', label: 'October'},
{value: '11', label: 'November'},
{value: '12', label: 'December'}
{value: '', label: i18n.t('Month')},
{value: '01', label: i18n.t('January')},
{value: '02', label: i18n.t('February')},
{value: '03', label: i18n.t('March')},
{value: '04', label: i18n.t('April')},
{value: '05', label: i18n.t('May')},
{value: '06', label: i18n.t('June')},
{value: '07', label: i18n.t('July')},
{value: '08', label: i18n.t('August')},
{value: '09', label: i18n.t('September')},
{value: '10', label: i18n.t('October')},
{value: '11', label: i18n.t('November')},
{value: '12', label: i18n.t('December')}
];

var options = _.map(MONTHS, function(item) {
Expand Down Expand Up @@ -138,7 +141,7 @@ class ClinicUserEdit extends React.Component {
return (
<div className={styles.error}>
<span>
{this.props.createCustodialAccountErrorMessage}<i className={styles.iconClose} onClick={this.props.dismissCreateCustodialAccountError}></i>
{i18n.t(this.props.createCustodialAccountErrorMessage)}<i className={styles.iconClose} onClick={this.props.dismissCreateCustodialAccountError}></i>
</span>
</div>
);
Expand All @@ -151,7 +154,7 @@ class ClinicUserEdit extends React.Component {
return (
<div className={styles.error}>
<span>
{this.props.updateProfileErrorMessage}<i className={styles.iconClose} onClick={this.props.dismissUpdateProfileError}></i>
{i18n.t(this.props.updateProfileErrorMessage)}<i className={styles.iconClose} onClick={this.props.dismissUpdateProfileError}></i>
</span>
</div>
);
Expand All @@ -163,8 +166,8 @@ class ClinicUserEdit extends React.Component {
<select className={styles.monthInput} {...fields.month.input} disabled={fields.disabled}>
{options}
</select>
<input className={styles.dateInput} placeholder="Day" {...fields.day.input} type="text" disabled={fields.disabled}/>
<input className={styles.dateInput} placeholder="Year" {...fields.year.input} type="text" disabled={fields.disabled}/>
<input className={styles.dateInput} placeholder={i18n.t('Day')} {...fields.day.input} type="text" disabled={fields.disabled}/>
<input className={styles.dateInput} placeholder={i18n.t('Year')} {...fields.year.input} type="text" disabled={fields.disabled}/>
</div>
{this.renderDateError(fields)}
</div>
Expand All @@ -185,7 +188,7 @@ class ClinicUserEdit extends React.Component {
render() {
const { handleSubmit, targetId, memberships } = this.props;
const isCustodialAccount = _.has(_.get(memberships, [targetId, 'permissions']), 'custodian');
const titleText = targetId ? 'Edit patient account' : 'Create a new patient account';
const titleText = targetId ? i18n.t('Edit patient account') : i18n.t('Create a new patient account');
const editable = targetId ? isCustodialAccount : true;

return (
Expand All @@ -201,37 +204,37 @@ class ClinicUserEdit extends React.Component {
<form className={styles.form} onSubmit={handleSubmit(this.handleNext)}>
<div className={styles.inputWrap}>
<label className={styles.inputLabel} htmlFor="name">
Patient Full Name
{i18n.t('Patient Full Name')}
</label>
<Field name="fullName" component={renderInput} props={{ disabled: !editable }} />
</div>
<div className={styles.inputWrap}>
<label className={styles.inputLabel} htmlFor="birthday">
Patient Birthdate
{i18n.t('Patient Birthdate')}
</label>
<Fields names={['month', 'day', 'year']} component={this.renderDateInputs} props={{ disabled: !editable }} />
</div>
<div className={styles.inputWrap}>
<label className={styles.inputLabel} htmlFor="mrn">
MRN (optional)
{i18n.t('MRN (optional)')}
</label>
<Field name="mrn" component={renderInput} props={{ disabled: !editable }} />
</div>
<div className={styles.inputWrap}>
<label className={styles.inputLabel} htmlFor="email">
Patient Email (optional)
{i18n.t('Patient Email (optional)')}
</label>
<Field name="email" component={renderInput} props={{ disabled: !editable }} />
</div>
<div className={styles.actions}>
<div>
<button type="submit" className={styles.button} disabled={!editable}>
Save
{i18n.t('Save')}
</button>
</div>
<div>
<div className={styles.cancel} onClick={this.handleCancel}>
Cancel
{i18n.t('Cancel')}
</div>
</div>
{this.renderCreateError()}
Expand Down
11 changes: 7 additions & 4 deletions app/components/ClinicUserSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ var metrics = require('../constants/metrics');

var styles = require('../../styles/components/ClinicUserSelect.module.less');

import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

class ClinicUserSelect extends React.Component {
static propTypes = {
allUsers: PropTypes.object.isRequired,
Expand Down Expand Up @@ -99,7 +102,7 @@ class ClinicUserSelect extends React.Component {
return (
<Select
name={'uploadTargetSelect'}
placeholder={'Search'}
placeholder={i18n.t('Search')}
className={styles.Select}
clearable={false}
simpleValue={true}
Expand All @@ -120,7 +123,7 @@ class ClinicUserSelect extends React.Component {
});
return (
<div className={classes} disabled={!this.props.targetId} onClick={this.handleClickNext}>
Next
{i18n.t('Next')}
</div>
);
};
Expand All @@ -132,7 +135,7 @@ class ClinicUserSelect extends React.Component {
return (
<div className={classes} onClick={this.props.onAddUserClick}>
<i className={styles.addIcon}></i>
Add new
{i18n.t('Add new')}
</div>
);
};
Expand All @@ -143,7 +146,7 @@ class ClinicUserSelect extends React.Component {
<div className={styles.wrapInner}>
<div className={styles.headerWrap}>
<div className={styles.header}>
Who are you uploading for?
{i18n.t('Who are you uploading for?')}
</div>
{this.renderAddNew()}
</div>
Expand Down
6 changes: 4 additions & 2 deletions app/components/DeviceSelection.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ var PropTypes = require('prop-types');
var React = require('react');
var cx = require('classnames');
var node_os = require('os');
import { remote } from 'electron';
const i18n = remote.getGlobal( 'i18n' );

import { urls } from '../constants/otherConstants';

Expand Down Expand Up @@ -110,15 +112,15 @@ class DeviceSelection extends React.Component {
return (
<div>
<div className={styles.main}>
<h3 className={styles.headline}>Choose devices</h3>
<h3 className={styles.headline}>{i18n.t('Choose devices')}</h3>
<form className={formClasses}>{items}</form>
</div>
<div className={styles.buttonWrap}>
<button type="submit"
className={styles.button}
onClick={this.handleSubmit}
disabled={disabled}>
Done
{i18n.t('Done')}
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit e662775

Please sign in to comment.