Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format utils cleanup #71

Merged
merged 15 commits into from
May 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@
+ [utilities](src/utils/README.md)
+ [API docs for utilities](src/utils/apidocs/README.md)
+ [datetime](src/utils/apidocs/datetime.md)
+ [format](src/utils/apidocs/format.md)
+ [misc](src/utils/apidocs/misc.md)
+ [misc](docs/misc/README.md)
+ [Time-rendering modes](docs/misc/TimeRenderingModes.md)
57 changes: 33 additions & 24 deletions docs/DirectoryStructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

* * * * *

As of November, 2016, the directory structure is as follows (although this may change as we continue to develop new code in this repository):
As of May, 2017, the directory structure is as follows (although this may change as we continue to develop new code in this repository):

<!-- to generate the directory structure below use `tree -d --matchdirs -I '_book|coverage|dist|node_modules|web'` -->
```
Expand All @@ -27,48 +27,52 @@ As of November, 2016, the directory structure is as follows (although this may c
│   ├── omnipod
│   └── tandem
├── docs
│   ├── deps
│   ├── misc
│   └── views
│   └── images
├── local
├── src
│   ├── components
│   │   ├── common
│   │   │   └── controls
│   │   │   ├── controls
│   │   │   └── tooltips
│   │   ├── settings
│   │   │   └── common
│   │   └── trends
│   │   ├── cbg
│   │   └── common
│   ├── containers
│   │   ├── settings
│   │   └── trends
│   │   ├── common
│   │   └── smbg
│   ├── redux
│   │   ├── actions
│   │   ├── constants
│   │   └── reducers
│   ├── styles
│   └── utils
│   ├── apidocs
│   ├── settings
│   └── trends
├── stories
│   ├── components
│   │   ├── common
│   │   │   └── controls
│   │   │   ├── controls
│   │   │   └── tooltips
│   │   ├── settings
│   │   └── trends
│   │   └── common
│   └── containers
│   └── trends
│   └── helpers
├── storybook
└── test
├── components
│   ├── common
│   │   └── controls
│   │   ├── controls
│   │   └── tooltip
│   ├── settings
│   │   └── common
│   └── trends
│   ├── cbg
│   └── common
├── containers
│   ├── settings
│   └── trends
│   ├── common
│   └── smbg
├── helpers
├── redux
│   ├── actions
Expand All @@ -85,7 +89,6 @@ All active, non-tooling code in the repository is contained in `src/`, and `src/
```
└── src
├── components
├── containers
├── redux
├── styles
└── utils
Expand All @@ -96,35 +99,39 @@ All active, non-tooling code in the repository is contained in `src/`, and `src/
```
└── redux
├── actions
├── constants
└── reducers
```

Within `src/redux/`, the `actions/` and `reducers/` contain the actions and reducers specific to the components in this component library. An `index.js` file in each of these directories exports the set of actions and a root reducer for a consuming application to import and consume via `connect()`ed components (in the case of actions) and by adding the reducer as a branch of the consuming application's state tree.

In both `actions/` and `reducers/`, files should be grouped into sub-directories by ["view"](#views) or located in a directory called `common/` if the action(s) or reducer(s) is relevant to more than one view.

The `src/redux/constants/` directory at present contains just the `actionTypes.js` file, which exports (as individual named exports) the action type constants for every action defined in `actions/` as well as those of blip's actions that are relevant to the viz reducers.

### React component directories

Within `src/`, the `components/`, `containers/`, and (eventually) `views/` directories all contain the source for React components of various types and purposes.
Within `src/`, the `components/` directory contains the source for React components of various types and purposes.

Note that our convention for naming React component files is [PascalCase](https://en.wikipedia.org/wiki/PascalCase): `BGSlice`, `DailyContainer`, &c.

#### components
By convention, React components that meet most or all of the following criteria are considered "container" components and named as such—e.g., `TrendsContainer` and `CBGDateTracesAnimationContainer`.

`components/` contains the lowest level of component. For the most part, these components should be stateless and (albeit with some rare exceptions) coded as [stateless functional components](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components) rather than ES6 classes extending `React.Component`.
- implemented as a `class` extension of `React.Component` or `React.PureComponent` (rather than a pure functional component)
- needs only minimal or zero styles
- primarily performs data munging or other "business logic" (or animation logic) in response to data (i.e., props) changes, potentially storing internal derived state as a result
- renders other React components, *not* HTML or SVG elements

The distinction between a "container" and a "pure" component is admittedly a bit fuzzy[^a], but generally the purpose of a container is to perform logic to *prepare* for rendering and then pass the resulting state to one or more stateless functional components for pure rendering. For example, for the trends view, the `TrendsContainer` determines the blood glucose and time domains on mount and on every update, preserving the current time domain in view and arrays of `cbg` and `smbg` currently in view (given the time domain) in its state. At the next level down, the `TrendsSVGContainer` sets up the rendering "canvas" (actually an SVG element) and scales for rendering (given the dimensions of the "canvas"). Another hallmark of "container" components is that they often do *not* have any associated styles since their purpose is computation and set up, not rendering.

For the most part, *non*-"container" components should be stateless and (albeit with some rare exceptions) coded as [stateless functional components](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components) rather than ES6 classes extending `React.Component` or `React.PureComponent`.

Files should be grouped into sub-directories by ["view"](#views) and where necessary (because of a large number of components) into further sub-directories by datatype.

Components used in more than one view should be located in `common/`. Examples of common components are controls like the BGM <-> CGM toggle used in both the basics and trends views and, potentially, animation containers like the header + child component (proposed for new device settings and potentially useful as well for sections in the basics view) that will slide the child component in and out on click of the header.

CSS particular to a component should be written using [CSS modules](https://github.com/css-modules/css-modules) and contained in a file in the same directory and with the same name as the component, substituting the `.css` suffix for `.js`.

#### containers

`containers/` contains the mid-tier type of component. The distinction between a "container" and a "component" is a bit fuzzy, but generally the purpose of a container is to perform logic to *prepare* for rendering and then pass the resulting state to one or more stateless functional components for pure rendering. For example, for the trends view, the `TrendsContainer` determines the blood glucose and time domains on mount and on every update, preserving the current time domain in view and arrays of `cbg` and `smbg` currently in view (given the time domain) in its state. At the next level down, the `CBGTrendsContainer` sets up the rendering "canvas" (actually an SVG element) and scales for rendering (given the dimensions of the "canvas"). Another hallmark of "container" components is that they often do *not* have any associated styles since their purpose is computation and set up, not rendering.

Files should be grouped into sub-directories by ["view"](#views) or located in a directory called `common/` if applicable to more than one view.

#### views

`views/` is a proposal for the eventual location of a top-level container component for each of blip's major data visualizations: (currently) basics, daily, weekly, trends, and device settings. A "view" will encompass more than just the rendered visualization; the navigation sub-header (currently containing links for navigating between views and arrows for navigating along the time dimension) and footer (containing options for some views like grouping for the `smbg` version of the trends view) will also be part of a top-level view component since some header and footer controls are specific to certain views or have specific behavior on certain views.
Expand All @@ -150,3 +157,5 @@ In general, utilities should export individual constants, functions, &c, **not**
### The test directory

The `test/` directory mirrors the structure of `src/`. Our convention for naming test files is to use the same names but insert `.test` before the `.js` suffix. For example, the tests for a component `BGSlice.js` should be in a file named `BGSlice.test.js`. The tests for a `datetime.js` utility file should be in a file named `datetime.test.js`.

[^a]: Hence our decision to give up on organizing containers in a `src/containers/` directory distinct from `src/components/`.
2 changes: 1 addition & 1 deletion docs/FeatureOverview.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The device settings view is the simplest, showing just a relatively simple tabul

Because Tandem pumps require a quite different visual representation (as well as a different structure to the data model) to capture the way the settings are programmed, the release of support for Tandem pumps was our forcing function for writing new code to display the Tandem settings, and so we also reimplemented the device settings display for all other Tidepool-supported pumps.

A new feature added as part of the reimplementation is the preservation of open or collapsed basal schedules (or Tandem "timed profiles") even when the user navigates away from Device Settings to elsewhere in the app before coming back. Leveraging blip's Redux store to manage the state of each collapsible section made this feature-add quite easy. (See [@tidepool/viz's usage of Redux](./Redux.md) for more information on managing visualization state through blip's redux store.)
A new feature added as part of the reimplementation is the preservation of open or collapsed basal schedules (or Tandem "timed profiles") even when the user navigates away from Device Settings to elsewhere in the app before coming back. Leveraging blip's Redux store to manage the state of each collapsible section made this feature-add quite easy. (See [@tidepool/viz's usage of Redux](./deps/Redux.md) for more information on managing visualization state through blip's redux store.)

[💣 tech debt 💣] Only the most recent insulin pump settings are displayed, and a blip user cannot navigate along the datetime dimension at all to view older insulin pump settings.

Expand Down
2 changes: 1 addition & 1 deletion docs/StartHere.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ As you're getting ready to develop code in this repository, we recommend startin
- [planned architecture](./Architecture.md)
- [app & directory structure](./DirectoryStructure.md)
- [code style](./CodeStyle.md)
- [dependencies](./Dependencies.md)
- [dependencies](./deps/README.md)

The root-level [README]('../README.md') contains the nuts & bolts of installing, configuring, and commands to accomplish various tasks.

Expand Down
2 changes: 1 addition & 1 deletion docs/deps/React.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

Aside from [our general views on React best practices at Tidepool](http://developer.tidepool.io/docs/front-end/react/index.html 'Tidepool developer portal: React @ Tidepool'), to develop code in this repository you should:

- understand our division between [components, containers, and views](./DirectoryStructure.md#react-component-directories)
- understand our division between [components, "container" components, and views](../DirectoryStructure.md#react-component-directories)
- understand [how we use D3 and React together]('./D3.md')
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tidepool/viz",
"version": "0.7.16",
"version": "0.7.18",
"description": "Tidepool data visualization for diabetes device data.",
"keywords": [
"data visualization"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import React, { PropTypes, PureComponent } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import * as actions from '../../redux/actions/';
import { MGDL_UNITS, MMOLL_UNITS } from '../../utils/constants';
import * as actions from '../../../redux/actions/';
import { MGDL_UNITS, MMOLL_UNITS } from '../../../utils/constants';

import NonTandem from '../../components/settings/NonTandem';
import Tandem from '../../components/settings/Tandem';
import { DISPLAY_VIEW, PRINT_VIEW } from '../../components/settings/constants';
import NonTandem from '../NonTandem';
import Tandem from '../Tandem';
import { DISPLAY_VIEW, PRINT_VIEW } from '../../../components/settings/constants';

export class PumpSettingsContainer extends PureComponent {
static propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import _ from 'lodash';
import React, { PropTypes } from 'react';
import TransitionGroupPlus from 'react-transition-group-plus';

import CBGDateTraceAnimated from '../../components/trends/cbg/CBGDateTraceAnimated';
import CBGDateTraceAnimated from './CBGDateTraceAnimated';

const CBGDateTracesAnimationContainer = (props) => {
const { bgBounds, data, dates, topMargin, xScale, yScale } = props;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import _ from 'lodash';
import React, { PropTypes, PureComponent } from 'react';
import { range } from 'd3-array';

import { THIRTY_MINS, TWENTY_FOUR_HRS } from '../../utils/datetime';
import { THIRTY_MINS, TWENTY_FOUR_HRS } from '../../../utils/datetime';
import {
findBinForTimeOfDay, findOutOfRangeAnnotations, calculateCbgStatsForBin,
} from '../../utils/trends/data';
} from '../../../utils/trends/data';

import CBGMedianAnimated from '../../components/trends/cbg/CBGMedianAnimated';
import CBGSliceAnimated from '../../components/trends/cbg/CBGSliceAnimated';
import CBGMedianAnimated from './CBGMedianAnimated';
import CBGSliceAnimated from './CBGSliceAnimated';

export default class CBGSlicesContainer extends PureComponent {
static propTypes = {
Expand Down
16 changes: 10 additions & 6 deletions src/components/trends/common/FocusedRangeLabels.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import React, { PropTypes } from 'react';
import Tooltip from '../../common/tooltips/Tooltip';

import { MGDL_UNITS, MMOLL_UNITS } from '../../../utils/constants';
import { displayBgValue } from '../../../utils/format';
import { formatBgValue } from '../../../utils/format';
import { formatClocktimeFromMsPer24 } from '../../../utils/datetime';

import styles from './FocusedRangeLabels.css';
Expand All @@ -35,7 +35,7 @@ const FocusedRangeLabels = (props) => {
return null;
}

const { bgUnits, dataType } = props;
const { bgPrefs, dataType } = props;
const isCbg = dataType === 'cbg';
const dataBucket = isCbg ? 'focusedSlice' : 'focusedRange';
const { [dataBucket]: { data, position } } = props;
Expand Down Expand Up @@ -71,7 +71,7 @@ const FocusedRangeLabels = (props) => {
<Tooltip
content={
<span className={styles.number}>
{displayBgValue(data[top], bgUnits, data.outOfRangeThresholds)}
{formatBgValue(data[top], bgPrefs, data.outOfRangeThresholds)}
</span>
}
backgroundColor={'transparent'}
Expand All @@ -86,7 +86,7 @@ const FocusedRangeLabels = (props) => {
title={<span className={styles.explainerText}>{timeFrom} - {timeTo}</span>}
content={
<span className={styles.number}>
{`Average ${displayBgValue(data[center], bgUnits, data.outOfRangeThresholds)}`}
{`Average ${formatBgValue(data[center], bgPrefs, data.outOfRangeThresholds)}`}
</span>
}
offset={{ top: 0, horizontal: props.numberOffsets.horizontal }}
Expand All @@ -97,7 +97,7 @@ const FocusedRangeLabels = (props) => {
<Tooltip
content={
<span className={styles.number}>
{displayBgValue(data[bottom], bgUnits, data.outOfRangeThresholds)}
{formatBgValue(data[bottom], bgPrefs, data.outOfRangeThresholds)}
</span>
}
backgroundColor={'transparent'}
Expand All @@ -120,7 +120,11 @@ FocusedRangeLabels.defaultProps = {
};

FocusedRangeLabels.propTypes = {
bgUnits: PropTypes.oneOf([MGDL_UNITS, MMOLL_UNITS]).isRequired,
bgPrefs: PropTypes.shape({
bgUnits: PropTypes.oneOf([MGDL_UNITS, MMOLL_UNITS]).isRequired,
// only the bgUnits required in this component
// so leaving off specification of bgBounds shape
}).isRequired,
dataType: PropTypes.oneOf(['cbg', 'smbg']).isRequired,
focusedKeys: PropTypes.arrayOf(PropTypes.oneOf([
'firstQuartile',
Expand Down
Loading