Skip to content

Commit

Permalink
Merge pull request #774 from nasa/develop
Browse files Browse the repository at this point in the history
1.9.0 to master
  • Loading branch information
laurenfrederick committed May 27, 2020
2 parents df46acf + 0ad90f7 commit 1e3ab53
Show file tree
Hide file tree
Showing 124 changed files with 8,588 additions and 2,596 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"rules": {
"comma-dangle": ["error", "only-multiline"],
"space-before-function-paren": ["warn", {"anonymous": "ignore", "named": "ignore", "asyncArrow": "ignore"}],
"semi": [2, "always"],
"no-extra-semi": 2,
"semi-spacing": [2, { "before": false, "after": true }],
Expand Down
15 changes: 15 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
**Summary:** Summary of changes

Addresses [CUMULUS-XX: Develop amazing new feature](https://bugs.earthdata.nasa.gov/browse/CUMULUS-XXX)

## Changes

* Detailed list or prose of changes
* ...

## PR Checklist

- [ ] Update CHANGELOG
- [ ] Unit tests
- [ ] Adhoc testing
- [ ] Integration tests
65 changes: 62 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,59 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

## [v1.9.0]

### BREAKING CHANGES

- This dashboard version requires Cumulus API version >= v1.23.0

### Changed

- **CUMULUS-1888**
- On the Granules page, CSV data was being refreshed in the background alog with the rest
of the data based on the timer. This could take a long time, depending on the number of granules.
This has been changed so that the data is only fetched when the user clicks the "Download CSV" button.

- **CUMULUS-1913**
- Add datepicker to reconcilation-reports page

- **CUMULUS-1916**
- reconcilation-reports page now requires Cumulus API version >= v1.23.0

## [v1.8.1]

### Changed

- **CUMULUS-1816**
- Change Datepicker behavior on login. The default to "Recent" start/end dates
now only occurs on first login on the hompage.
- URL is updated on login to reflect Datepicker params

- **CUMULUS-1903**
- Replace individual tables in reconciliation report with tabs that change which table is displayed on click

- **CUMULUS-1920**
- Add additional columns to reconciliation report list

- **CUMULUS-1920**
- Updated styles for granule reingest modal

- **CUMULUS-1948**
- Add provider to Granules tables

### Fixed

- **CUMULUS-1881**
- Fix Elasticsearch query bug for Gateway Access Metrics

- **CUMULUS-1984**
- Fix bug where Distribution metrics were showing on the homepage even when
Elasaticsearch/Kibana not set up

- **CUMULUS-1988**
- Fix bugs in reducer-creators


## [v1.8.0]

### Added
Expand Down Expand Up @@ -66,12 +119,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- **CUMULUS-1787**
- Changes `listCollections` action to hit `/collections/active` endpoint when timefilters are present (requires Cumulus API v1.22.1)

- **CUMULUS-1790**
- Changes default values and visuals for home page's datepicker. When the page loads, it defauls to display "Recent" data, which is the previous 24 hours with no end time.

- **CUMULUS-1798**
- Change the 12HR/24HR Format selector from radio to dropdown
- Hide clock component in react-datetime-picker

- **CUMULUS-1790**
- Changes default values and visuals for home page's datepicker. When the page loads, it defauls to display "Recent" data, which is the previous 24 hours with no end time.
- **CUMULUS-1810**
- Unified the coding pattern used for creating Redux reducers to avoid
unnecessary object creation and reduce unnecessary UI component refreshes

### Fixed

Expand Down Expand Up @@ -352,7 +409,9 @@ Fix for serving the dashboard through the Cumulus API.

- Versioning and changelog [CUMULUS-197] by @kkelly51

[Unreleased]: https://github.com/nasa/cumulus-dashboard/compare/v1.8.0...HEAD
[Unreleased]: https://github.com/nasa/cumulus-dashboard/compare/v1.9.0...HEAD
[v1.9.0]: https://github.com/nasa/cumulus-dashboard/compare/v1.8.1...v1.9.0
[v1.8.1]: https://github.com/nasa/cumulus-dashboard/compare/v1.8.0...v1.8.1
[v1.8.0]: https://github.com/nasa/cumulus-dashboard/compare/v1.7.2...v1.8.0
[v1.7.2]: https://github.com/nasa/cumulus-dashboard/compare/v1.7.1...v1.7.2
[v1.7.1]: https://github.com/nasa/cumulus-dashboard/compare/v1.7.0...v1.7.1
Expand Down
68 changes: 59 additions & 9 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,70 @@ This sends the granule data to the store. We need to specify the primary key so
export const SET_GRANULE = 'SET_GRANULE';
```

Now in `reducers/api.js` we import the primary key and export a reducer function, which receives the current state, and the reducer in question. We use a primary key, because every action is sent to every reducer. The reducer doesn't manipulate the current state, but rather returns a new state object that includes the new data.
Now in `reducers/api.js` we import the primary key and export a reducer
function, which receives the current state, and the reducer in question. We
use a primary key, because every action is sent to every reducer. The reducer
doesn't manipulate the current state, but rather returns a new state object
that includes the new data.

Since it is critical to avoid directly mutating the current state in a reducer
function, we use the `createReducer` function from the
[Redux Toolkit](https://redux-toolkit.js.org/). This not only allows us to
avoid the more verbose `switch` statement syntax that is normally used without
the use of a convenience function such as `createReducer`, but also guarantees
that we never mutate the current state by providing a proxy state object
instead.

We can then conveniently mutate the proxy state object _as if_ we were mutating
the actual state object, and the underlying functionality takes care of
producing a new state object for us, with the fewest possible changes. The
general pattern for each reducer within the `app/src/js/reducers` directory is
as follows:

```javascript
import { SET_GRANULE } from '../actions';
export function reducer (currentState, action) {
const newState = Object.assign({}, currentState);
if (action.type === SET_GRANULE) {
newState.granuleDetail[action.id] = action.data;
}
return newState;
import { createReducer } from '@reduxjs/toolkit';
import {
ACTION_TYPE_1,
ACTION_TYPE_2,
...
ACTION_TYPE_N
} from '../actions/types';

export const initialState = {
// Some initial state object appropriate for the reducer
...
};

export default createReducer(initialState, {
[ACTION_TYPE_1]: (state, action) => {
state.path.to.prop1 = action.newValue1;
state.path.to.prop2 = action.newValue2;
},
[ACTION_TYPE_2]: (state, action) => {
...
},
...
[ACTION_TYPE_N]: (state, action) => {
...
}
});
```

Finally, this allows us to access the data from a component, where component state is passed as a `prop`:
Again, note that the `state` parameter for each of the case reducers above is
a proxy object, not the actual state object, but it can be mutated just as if
it were. Further, you will likely never return a completely new state object,
because that is the purpose of the proxy object instead. The library manages
the creation of a new object on your behalf. Of course, if it is absolutely
necessary for some reason to return a new object, you may, but do _not_ mutate
the proxy _and also_ return a new object. For more details, see
[createReducer](https://redux-toolkit.js.org/api/createReducer).

To reduce some common boilerplate code in the case reducers, there are a few
convenience reducer creators in `app/src/js/reducers/utils/reducer-creators.js`.
See the documentation in that file for more information.

Finally, this allows us to access the data from a component, where component
state is passed as a `prop`:

```javascript
// import the action so we can call it
Expand Down
8 changes: 4 additions & 4 deletions TABLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ A basic table component that supports row selection and dumb sorting (see below)
* Additional options can be found [here](https://github.com/tannerlinsley/react-table/blob/master/docs/api/useTable.md#column-options) or in the documation for a specific plugin hook

- **data**: Array of data items. Items can be any format.
- **sortIdx**: The id of the column to sort on.
- **changeSortProps**: Callback when a new sort order is defined, passed an object with the properties `{ sortIdx, order }`.
- **sortId**: The id of the column to sort on.
- **changeSortProps**: Callback when a new sort order is defined, passed an object with the properties `{ sortId, order }`.
- **onSelect**: Callback when a row is selected (or unselected), passed an array containing the ids of all selected rows.
- **canSelect**: Boolean value defining whether 1. rows can be selected and 2. to render check marks.
- **rowId**: String or function that defines a particular row's id. Passed to `useTable` options via `getRowId`.

Note, `sortIdx` and `changeSortProps` only apply to components that implement smart searching, such as `list-view`. This base component does internal prop checking to determine whether it uses smart or dumb sorting, based on whether the above props are defined.
Note, `sortId` and `changeSortProps` only apply to components that implement smart searching, such as `list-view`. This base component does internal prop checking to determine whether it uses smart or dumb sorting, based on whether the above props are defined.

## `list-view`

Expand All @@ -38,7 +38,7 @@ Wraps `sortable-table` and implements auto-update and smart sort. When a new sor
- **list**: Parent data structure, ie `state.granules.list` or `state.collections.list`. Expected to contain `{ data, inflight, error, meta }` properties corresponding to all `list` state objects.
- **dispatch**: Redux dispatch function.
- **action**: Redux-style action to send, ie `listCollections`.
- **sortIdx**: Corresponds to `sortableTable#sortIdx`.
- **sortId**: Corresponds to `sortableTable#sortId`.
- **query**: Array of configuration objects passed to `batch-async-command`.
- **rowId** Corresponds to `sortableTable#rowId`.

Expand Down
21 changes: 21 additions & 0 deletions app/src/css/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,27 @@ a:active {
}
}

/**************************************************
Status Indicator
**************************************************/

.status-indicator {
display: inline-block;
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
background-color: $grey;
margin-right: 0.5em;

&--success {
background-color: $light-green;
}

&--failed {
background-color: $error-red;
}
}

/**************************************************
Table
**************************************************/
Expand Down
6 changes: 6 additions & 0 deletions app/src/css/modules/_modals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@

li {
font-weight: bold;

.Collapsible__contentInner {
font-weight: normal;
max-width: none;
color: $error-red;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions app/src/css/vendor/bootstrap/_bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and behaviors for our Cumulus Dashboard components

/* Bootstrap Overrides */
@import "overrides/breadcrumb";
@import "overrides/card";
@import "overrides/pagination";
@import "overrides/modal";

Expand Down
28 changes: 28 additions & 0 deletions app/src/css/vendor/bootstrap/overrides/_card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.card-wrapper {
display: flex;
justify-content: space-between;
}

.card {
width: 10em;
cursor: pointer;

.card-header {
color: $white;
background-color: $grey;
}

.h5 {
font-size: 1.25rem;
}

&:hover {
box-shadow: $shadow__hover;
}

&.active {
.card-header {
background-color: $theme--blue;
}
}
}
4 changes: 2 additions & 2 deletions app/src/js/actions/action-config/apiGatewaySearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ export const apiGatewaySearchTemplate = (prefix, startTimeEpochMilli, endTimeEpo
},
"ApiAccessErrors": {
"query_string": {
"query": "status:[400 TO 599]",
"query": "statusCode:[400 TO 599]",
"analyze_wildcard": true,
"default_field": "*"
}
},
"ApiAccessSuccesses": {
"query_string": {
"query": "status:[200 TO 399]",
"query": "statusCode:[200 TO 399]",
"analyze_wildcard": true,
"default_field": "*"
}
Expand Down
47 changes: 30 additions & 17 deletions app/src/js/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,27 @@ export const refreshAccessToken = (token) => {
export const setTokenState = (token) => ({ type: types.SET_TOKEN, token });

export const interval = function (action, wait, immediate) {
if (immediate) { action(); }
if (immediate) {
action();
}
const intervalId = setInterval(action, wait);
return () => clearInterval(intervalId);
};

export const getCollection = (name, version) => ({
[CALL_API]: {
type: types.COLLECTION,
method: 'GET',
id: getCollectionId({ name, version }),
path: `collections?name=${name}&version=${version}`
}
});
export const getCollection = (name, version) => {
return (dispatch, getState) => {
const timeFilters = fetchCurrentTimeFilters(getState().datepicker);
return dispatch({
[CALL_API]: {
type: types.COLLECTION,
method: 'GET',
id: getCollectionId({ name, version }),
path: `collections?name=${name}&version=${version}`,
qs: timeFilters,
},
});
};
};

export const getApiVersion = () => {
return (dispatch) => {
Expand Down Expand Up @@ -915,14 +923,19 @@ export const clearRulesSearch = () => ({ type: types.CLEAR_RULES_SEARCH });
export const filterRules = (param) => ({ type: types.FILTER_RULES, param: param });
export const clearRulesFilter = (paramKey) => ({ type: types.CLEAR_RULES_FILTER, paramKey: paramKey });

export const listReconciliationReports = (options) => ({
[CALL_API]: {
type: types.RECONCILIATIONS,
method: 'GET',
url: new URL('reconciliationReports', root).href,
qs: Object.assign({ limit: defaultPageLimit }, options)
}
});
export const listReconciliationReports = (options) => {
return (dispatch, getState) => {
const timeFilters = fetchCurrentTimeFilters(getState().datepicker);
return dispatch({
[CALL_API]: {
type: types.RECONCILIATIONS,
method: 'GET',
url: new URL('reconciliationReports', root).href,
qs: Object.assign({ limit: defaultPageLimit }, options, timeFilters)
}
});
};
};

export const getReconciliationReport = (reconciliationName) => ({
[CALL_API]: {
Expand Down
4 changes: 4 additions & 0 deletions app/src/js/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,7 @@ export const PROCESSING_MODAL = 'PROCESSING_MODAL';
export const DATEPICKER_DROPDOWN_FILTER = 'DATEPICKER_DROPDOWN_FILTER';
export const DATEPICKER_DATECHANGE = 'DATEPICKER_DATECHANGE';
export const DATEPICKER_HOUR_FORMAT = 'DATEPICKER_HOUR_FORMAT';
// timer state
export const TIMER_STOP = 'TIMER_STOP';
export const TIMER_START = 'TIMER_START';
export const TIMER_SET_COUNTDOWN = 'TIMER_SET_COUNTDOWN';
Loading

0 comments on commit 1e3ab53

Please sign in to comment.