Skip to content

Commit

Permalink
Prototype Datasets Support (#35)
Browse files Browse the repository at this point in the history
* add Neon API and Environment support for prototype endpoints

* new alias for DataThemeIcon / land cover

* add prorotype manifest method to NeonApi

* NeonApi hook for prototype manifest rollup

* fix sitemap tiling on nav-to issue

* display sites from props including decommissioned (map only)

* sitemap table works with manual/decom locations

* expand SiteMapUtils unit tests to cover latest

* finalize manual locations on sitemap, lib export

* restore SiteMap examples on styleguide

* fix sitemap manual data context hydration load order bug

* complete SiteMapUtils unit testing

* lib export for latest sitemap updates

* latest site names; fix availability selection handle lag bug

* add citation meta tag injection via JSON-LD

* NeonEnvironment unit tests and hardening

* DownloadDataContext unit tests; lint; lib export

* begin streamlining SiteMapTable presentation

* SiteMap Table cleaner / more efficient initial load

* SiteMap split view and improved StyleGuide

* Update packages

* fix packages, SiteMap table double scroll where apropos

* fix resizing on sitemaptable second scrollbar

* TimeSeriesViewer invalidate defaults + handle 0 variance series

* NeonContext fetchPartials prop; v1.6.4

Co-authored-by: jsampson <jsampson@battelleecology.org>
  • Loading branch information
Frencil and sampsonj authored Mar 10, 2021
1 parent 3128710 commit 9b5dd6d
Show file tree
Hide file tree
Showing 82 changed files with 5,254 additions and 2,063 deletions.
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ REACT_APP_NEON_PATH_MANIFEST_API="/api/download/v0"
REACT_APP_NEON_PATH_DOWNLOAD_API="/api/download/v0"
REACT_APP_NEON_PATH_AOP_DOWNLOAD_API="/browse-data"
REACT_APP_NEON_PATH_DATA_API="/data"
REACT_APP_NEON_PATH_PROTOTYPE_DATA_API="/prototype"
REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS="/file-naming-conventions"

REACT_APP_NEON_PATH_PUBLIC_GRAPHQL="/graphql"
Expand Down
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ REACT_APP_NEON_PATH_MANIFEST_API="/api/download/v0"
REACT_APP_NEON_PATH_DOWNLOAD_API="/api/download/v0"
REACT_APP_NEON_PATH_AOP_DOWNLOAD_API="/browse-data"
REACT_APP_NEON_PATH_DATA_API="/data"
REACT_APP_NEON_PATH_PROTOTYPE_DATA_API="/prototype"
REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS="/file-naming-conventions"

REACT_APP_NEON_PATH_PUBLIC_GRAPHQL="/graphql"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ var TIME = {
};
exports.TIME = TIME;
TIME.MIN_YEAR_MONTH = "".concat(TIME.START_YEAR, "-01");
TIME.MAX_YEAR_MONTH = "".concat(TIME.endYear, "-12");
TIME.MAX_YEAR_MONTH = "".concat(TIME.END_YEAR, "-12");
TIME.YEARS = Array(TIME.END_YEAR - TIME.START_YEAR + 1).fill(0).map(function (val, idx) {
return TIME.START_YEAR + idx;
});
Expand Down
101 changes: 69 additions & 32 deletions lib/components/DataProductAvailability/BasicAvailabilityGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ function BasicAvailabilityGrid(config) {

var getYearStartX = function getYearStartX(year) {
var intYear = parseInt(year, 10);
return getLabelWidth() + _AvailabilityUtils.SVG.END_PADDING + _AvailabilityUtils.TIME.YEARS.indexOf(intYear) * _AvailabilityUtils.SVG.YEAR_WIDTH + _AvailabilityUtils.TIME.YEARS.indexOf(intYear) * _AvailabilityUtils.SVG.YEAR_PADDING;
return getLabelWidth() + _AvailabilityUtils.SVG.END_PADDING + _AvailabilityUtils.TIME.YEARS.indexOf(intYear) * (_AvailabilityUtils.SVG.YEAR_WIDTH + _AvailabilityUtils.SVG.YEAR_PADDING);
};

var getYearCenterX = function getYearCenterX(year) {
Expand Down Expand Up @@ -382,40 +382,74 @@ function BasicAvailabilityGrid(config) {
}
}; // Get the yearMonth string that's next to a given yearMonth on either side.
// Stays within the selectable range unless selectable is false, in which case
// is stays within the chart's global min and max.


var getAdjacentYearMonth = function getAdjacentYearMonth(yearMonth) {
var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'left';
var selectable = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var year = parseInt(yearMonth.substr(0, 4), 10);
var month = parseInt(yearMonth.substr(5, 2), 10);
var bounds = selectable ? dateRange.validValues : [_AvailabilityUtils.TIME.MIN_YEAR_MONTH, _AvailabilityUtils.TIME.MAX_YEAR_MONTH];
var adjacent = yearMonth;
// it stays within the chart's global min and max.

/*
const getAdjacentYearMonth = (yearMonth, side = 'left', selectable = true) => {
const year = parseInt(yearMonth.substr(0, 4), 10);
const month = parseInt(yearMonth.substr(5, 2), 10);
const bounds = selectable ? dateRange.validValues : [TIME.MIN_YEAR_MONTH, TIME.MAX_YEAR_MONTH];
let adjacent = yearMonth;
switch (side) {
case 'left':
if (month === 1) {
adjacent = "".concat(year - 1, "-12");
adjacent = `${year - 1}-12`;
} else {
adjacent = "".concat(year, "-").concat((month - 1).toString().padStart(2, '0'));
adjacent = `${year}-${(month - 1).toString().padStart(2, '0')}`;
}

return adjacent < bounds[0] ? bounds[0] : adjacent;

case 'right':
if (month === 12) {
adjacent = "".concat(year + 1, "-01");
adjacent = `${year + 1}-01`;
} else {
adjacent = "".concat(year, "-").concat((month + 1).toString().padStart(2, '0'));
adjacent = `${year}-${(month + 1).toString().padStart(2, '0')}`;
}

return adjacent > bounds[1] ? bounds[1] : adjacent;

default:
return adjacent;
}
};
*/
// Get the string for the yearmonth closest to a given pixel x-offset on either side.
// Stays within the selectable range unless selectable is false, in which case
// it stays within the chart's global min and max.


var getXOffsetYearMonth = function getXOffsetYearMonth(xOffset, dragOffset) {
var side = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'left';
var selectable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;

/***/
var basis = Math.min(Math.max(xOffset, getLabelWidth()), svgWidth) - dragOffset;
var yearIdx = Math.floor((basis - getLabelWidth()) / (_AvailabilityUtils.SVG.YEAR_WIDTH + _AvailabilityUtils.SVG.YEAR_PADDING));
var boundedYearIdx = Math.max(Math.min(yearIdx, _AvailabilityUtils.TIME.YEARS.length - 1), 0);
var year = _AvailabilityUtils.TIME.YEARS[boundedYearIdx];
var yearStartX = getYearStartX(year);

if (basis < yearStartX && side === 'left' && boundedYearIdx !== 0) {
year = parseInt(year, 10) - 1;
yearStartX = getYearStartX(year);
} else if (basis > yearStartX + _AvailabilityUtils.SVG.YEAR_WIDTH && side === 'right' && boundedYearIdx !== _AvailabilityUtils.TIME.YEARS.length - 1) {
year = parseInt(year, 10) + 1;
yearStartX = getYearStartX(year);
}

var roundFunc = side === 'left' ? 'floor' : 'ceil';
var month = Math[roundFunc]((basis - yearStartX) / _AvailabilityUtils.SVG.YEAR_MONTH_WIDTH) + 1;
var boundedMonth = Math.max(Math.min(month, 12), 1);
var yearMonth = "".concat(year, "-").concat(boundedMonth.toString().padStart(2, '0'));
var bounds = selectable ? dateRange.validValues : [_AvailabilityUtils.TIME.MIN_YEAR_MONTH, _AvailabilityUtils.TIME.MAX_YEAR_MONTH];

if (yearMonth < bounds[0]) {
return bounds[0];
}

if (yearMonth > bounds[1]) {
return bounds[1];
}

return yearMonth;
};
/**
SVG: Row Hover
*/
Expand Down Expand Up @@ -730,7 +764,8 @@ function BasicAvailabilityGrid(config) {
return "dateRange".concat(d === 0 ? 'Start' : 'End', "MaskRect");
}).attr('x', function (d) {
return getYearMonthGutterX(dateRange.value[d] || _AvailabilityUtils.TIME.MIN_YEAR_MONTH, d === 0 ? 'left' : 'right') - _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2 + getTimeOffset();
}).attr('y', 0).attr('width', _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH).attr('height', svgHeight).style('cursor', 'ew-resize').style('outline', 'none').attr('fill', 'red').style('opacity', 0).style('display', sites.value.length ? null : 'none');
}).attr('y', 0).attr('width', _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH).attr('height', svgHeight).style('cursor', 'crosshair') // 'ew-resize'
.style('outline', 'none').attr('fill', 'red').style('opacity', 0).style('display', sites.value.length ? null : 'none');
};
/**
SVG: Selections
Expand Down Expand Up @@ -902,16 +937,17 @@ function BasicAvailabilityGrid(config) {
draggingDateRange[0].centerDragX = parseFloat(dragDateRangeStartMask.attr('x'), 10) + _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2;
}).on('drag', function () {
draggingDateRange[0].centerDragX += _d3Selection.event.dx;
dragDateRangeStartMask.attr('x', draggingDateRange[0].centerDragX - _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2);
var adjacentYearMonth = getAdjacentYearMonth(dateRange.value[0], _d3Selection.event.dx > 0 ? 'right' : 'left');
var adjacentYearMonthStartX = getYearMonthGutterX(adjacentYearMonth, 'left');
var centerDragX = draggingDateRange[0].centerDragX;
dragDateRangeStartMask.attr('x', centerDragX - _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2);
var nextYearMonth = getXOffsetYearMonth(centerDragX, getTimeOffset(), 'right');
var nextYearMonthStartX = getYearMonthGutterX(nextYearMonth, 'left');
var currentYearMonthStartX = getYearMonthGutterX(dateRange.value[0], 'left');
var insideClipCenterDragX = draggingDateRange[0].centerDragX - getTimeOffset();
var distanceToAdjacent = Math.abs(insideClipCenterDragX - adjacentYearMonthStartX);
var distanceToNext = Math.abs(insideClipCenterDragX - nextYearMonthStartX);
var distanceToCurrent = Math.abs(insideClipCenterDragX - currentYearMonthStartX);

if (adjacentYearMonth !== dateRange.value[0] && distanceToAdjacent < distanceToCurrent) {
dateRange.value[0] = adjacentYearMonth;
if (nextYearMonth !== dateRange.value[0] && distanceToNext < distanceToCurrent) {
dateRange.value[0] = nextYearMonth;
redrawSelections();
}
}).on('end', function () {
Expand All @@ -937,16 +973,17 @@ function BasicAvailabilityGrid(config) {
draggingDateRange[1].centerDragX = parseFloat(dragDateRangeEndMask.attr('x'), 10) + _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2;
}).on('drag', function () {
draggingDateRange[1].centerDragX += _d3Selection.event.dx;
dragDateRangeEndMask.attr('x', draggingDateRange[1].centerDragX - _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2);
var adjacentYearMonth = getAdjacentYearMonth(dateRange.value[1], _d3Selection.event.dx > 0 ? 'right' : 'left');
var adjacentYearMonthEndX = getYearMonthGutterX(adjacentYearMonth, 'right');
var centerDragX = draggingDateRange[1].centerDragX;
dragDateRangeEndMask.attr('x', centerDragX - _AvailabilityUtils.SVG.DATE_RANGE_MASK_WIDTH / 2);
var nextYearMonth = getXOffsetYearMonth(centerDragX, getTimeOffset(), 'left');
var nextYearMonthEndX = getYearMonthGutterX(nextYearMonth, 'right');
var currentYearMonthEndX = getYearMonthGutterX(dateRange.value[1], 'right');
var insideClipCenterDragX = draggingDateRange[1].centerDragX - getTimeOffset();
var distanceToAdjacent = Math.abs(insideClipCenterDragX - adjacentYearMonthEndX);
var distanceToNext = Math.abs(insideClipCenterDragX - nextYearMonthEndX);
var distanceToCurrent = Math.abs(insideClipCenterDragX - currentYearMonthEndX);

if (adjacentYearMonth !== dateRange.value[1] && distanceToAdjacent < distanceToCurrent) {
dateRange.value[1] = adjacentYearMonth;
if (nextYearMonth !== dateRange.value[1] && distanceToNext < distanceToCurrent) {
dateRange.value[1] = nextYearMonth;
redrawSelections();
}
}).on('end', function () {
Expand Down
7 changes: 6 additions & 1 deletion lib/components/DataThemeIcon/DataThemeIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var dataThemes = {
},
landcover: {
title: 'Land Cover & Processes',
aliases: ['landuse', 'Land Use, Land Cover, and Land Processes'],
aliases: ['landuse', 'Land Cover and Processes', 'Land Use, Land Cover, and Land Processes'],
src: _landcover.default
},
organisms: {
Expand All @@ -81,6 +81,11 @@ var DataThemeIcon = function DataThemeIcon(props) {
var dataTheme = dataThemes[theme] || Object.values(dataThemes).find(function (entry) {
return theme === entry.title || entry.aliases.includes(theme);
});

if (!dataTheme) {
return null;
}

var elementProps = {
src: dataTheme.src,
alt: dataTheme.title,
Expand Down
4 changes: 4 additions & 0 deletions lib/components/DownloadDataContext/DownloadDataContext.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export function getTestableItems(): {
regenerateS3FilesFiltersAndValidValues?: undefined;
getAndValidateNewState?: undefined;
ALL_POSSIBLE_VALID_DATE_RANGE?: undefined;
ALL_POSSIBLE_VALID_DOCUMENTATION?: undefined;
ALL_POSSIBLE_VALID_PACKAGE_TYPE?: undefined;
} | {
productDataIsValid: (productData: any) => boolean;
yearMonthIsValid: (yearMonth?: string) => boolean;
Expand Down Expand Up @@ -102,6 +104,8 @@ export function getTestableItems(): {
regenerateS3FilesFiltersAndValidValues: (state: any) => any;
getAndValidateNewState: (previousState: any, action: any, broadcast?: boolean) => any;
ALL_POSSIBLE_VALID_DATE_RANGE: string[];
ALL_POSSIBLE_VALID_DOCUMENTATION: string[];
ALL_POSSIBLE_VALID_PACKAGE_TYPE: string[];
};
declare namespace DownloadDataContext {
export { Provider };
Expand Down
4 changes: 3 additions & 1 deletion lib/components/DownloadDataContext/DownloadDataContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,9 @@ var getTestableItems = function getTestableItems() {
getAndValidateNewS3FilesState: getAndValidateNewS3FilesState,
regenerateS3FilesFiltersAndValidValues: regenerateS3FilesFiltersAndValidValues,
getAndValidateNewState: getAndValidateNewState,
ALL_POSSIBLE_VALID_DATE_RANGE: ALL_POSSIBLE_VALID_DATE_RANGE
ALL_POSSIBLE_VALID_DATE_RANGE: ALL_POSSIBLE_VALID_DATE_RANGE,
ALL_POSSIBLE_VALID_DOCUMENTATION: ALL_POSSIBLE_VALID_DOCUMENTATION,
ALL_POSSIBLE_VALID_PACKAGE_TYPE: ALL_POSSIBLE_VALID_PACKAGE_TYPE
};
};

Expand Down
4 changes: 4 additions & 0 deletions lib/components/NeonApi/NeonApi.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ declare namespace NeonApi {
export function getJson(url: string, callback: any, errorCallback: any, cancellationSubject$: any, headers?: Object | undefined): import("rxjs").Subscription;
export function getProductsObservable(): import("rxjs").Observable<any>;
export function getProductObservable(productCode: string, release?: string): import("rxjs").Observable<any>;
export function getPrototypeDatasetsObservable(): import("rxjs").Observable<any>;
export function getPrototypeDatasetObservable(uuid: any): import("rxjs").Observable<any>;
export function getPrototypeManifestRollupObservable(uuid: any): import("rxjs").Observable<any>;
export function getPrototypeDataFileObservable(uuid: any, fileName: any): import("rxjs").Observable<any>;
export function getReleasesObservable(): import("rxjs").Observable<any>;
export function getReleaseObservable(release: string): import("rxjs").Observable<any>;
export function getSitesJsonObservable(): import("rxjs").Observable<any>;
Expand Down
19 changes: 19 additions & 0 deletions lib/components/NeonApi/NeonApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,25 @@ var NeonApi = {
return _getJsonObservable(path);
},

/**
* Gets the prototype data endpoint RxJS Observable.
* @return The RxJS Ajax Observable
*/
getPrototypeDatasetsObservable: function getPrototypeDatasetsObservable() {
return _getJsonObservable("".concat(_NeonEnvironment.default.getFullApiPath('prototype'), "/datasets"));
},
getPrototypeDatasetObservable: function getPrototypeDatasetObservable(uuid) {
return _getJsonObservable("".concat(_NeonEnvironment.default.getFullApiPath('prototype'), "/datasets/").concat(uuid));
},
getPrototypeManifestRollupObservable: function getPrototypeManifestRollupObservable(uuid) {
return (// eslint-disable-next-line max-len
_getJsonObservable("".concat(_NeonEnvironment.default.getFullApiPath('manifest'), "/prototype/manifest/rollup?uuid=").concat(uuid))
);
},
getPrototypeDataFileObservable: function getPrototypeDataFileObservable(uuid, fileName) {
return _getJsonObservable("".concat(_NeonEnvironment.default.getFullApiPath('prototype'), "/data/").concat(uuid, "/").concat(fileName));
},

/**
* Gets the release endpoint RxJS Observable.
* @return The RxJS Ajax Observable
Expand Down
6 changes: 3 additions & 3 deletions lib/components/NeonContext/NeonContext.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ declare namespace Provider {
export { ProviderPropTypes as propTypes };
export namespace defaultProps {
export const children: null;
export const fetchPartials: boolean;
export const useCoreAuth: boolean;
export const useCoreHeader: boolean;
export function whenFinal(): void;
}
}
Expand Down Expand Up @@ -1048,10 +1048,10 @@ declare function getWrappedComponent(Component: any): (props: any) => JSX.Elemen
declare namespace ProviderPropTypes {
const children_1: PropTypes.Requireable<string | number | boolean | {} | PropTypes.ReactElementLike | PropTypes.ReactNodeArray>;
export { children_1 as children };
const fetchPartials_1: PropTypes.Requireable<boolean>;
export { fetchPartials_1 as fetchPartials };
const useCoreAuth_1: PropTypes.Requireable<boolean>;
export { useCoreAuth_1 as useCoreAuth };
const useCoreHeader_1: PropTypes.Requireable<boolean>;
export { useCoreHeader_1 as useCoreHeader };
const whenFinal_1: PropTypes.Requireable<(...args: any[]) => any>;
export { whenFinal_1 as whenFinal };
}
Expand Down
8 changes: 4 additions & 4 deletions lib/components/NeonContext/NeonContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ var Provider = function Provider(props) {
var _fetchMethods;

var children = props.children,
fetchPartials = props.fetchPartials,
useCoreAuth = props.useCoreAuth,
useCoreHeader = props.useCoreHeader,
whenFinal = props.whenFinal;
var initialState = (0, _cloneDeep.default)(DEFAULT_STATE);
initialState.isActive = true;
Expand All @@ -311,7 +311,7 @@ var Provider = function Provider(props) {
initialState.fetches.auth.status = FETCH_STATUS.AWAITING_CALL;
}

if (!useCoreHeader) {
if (fetchPartials) {
initialState.fetches[DRUPAL_HEADER_HTML].status = FETCH_STATUS.AWAITING_CALL;
initialState.fetches[DRUPAL_FOOTER_HTML].status = FETCH_STATUS.AWAITING_CALL;
}
Expand Down Expand Up @@ -467,15 +467,15 @@ var Provider = function Provider(props) {

var ProviderPropTypes = {
children: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.string])), _propTypes.default.node, _propTypes.default.string]),
fetchPartials: _propTypes.default.bool,
useCoreAuth: _propTypes.default.bool,
useCoreHeader: _propTypes.default.bool,
whenFinal: _propTypes.default.func
};
Provider.propTypes = ProviderPropTypes;
Provider.defaultProps = {
children: null,
fetchPartials: false,
useCoreAuth: false,
useCoreHeader: false,
whenFinal: function whenFinal() {}
};
/**
Expand Down
4 changes: 2 additions & 2 deletions lib/components/NeonEnvironment/NeonEnvironment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ declare namespace NeonEnvironment {
export namespace route {
export function home(): string;
export function account(): string;
export function getFullRoute(route: any): string;
export function buildRouteFromHost(route: any): string;
export function getFullRoute(route?: string): string;
export function buildRouteFromHost(route?: string): string;
export function buildHomeRoute(): string;
export function buildAccountRoute(): string;
}
Expand Down
Loading

0 comments on commit 9b5dd6d

Please sign in to comment.