From 7b0b5e6bdfc7c370ff4809bdd968ecc26628a753 Mon Sep 17 00:00:00 2001 From: Jeremy Sampson Date: Fri, 16 Jul 2021 13:02:01 -0600 Subject: [PATCH] v1.8.0 (#40) * Added Neon public API host variable with value pulled from server data. * Fixed function name. * Updates for setting public API host through server data. * Updated valid hosts regex pattern. * Reset NEON_SERVER_DATA * Minor cleanup. * Update for web socket host determination. * Added prototype typescript environment module. * Cleanup. * Fixed test and cleanup. * Removed unused variable. * Removed file. * site map: handle maxZoom property propagation * site map: update mapZoom initialization to include bounds * NeonContext final state when core auth, TS context include release * resolve authentication state when silent SSO disabled * pull out route handling to dedicated service * fix host regex validation, update routes * reduce .env usage * fix account route * fix logout redirect path handling * improve auth logout redirection * update login redirect path handling * handle fallback cases for auth redirects * bump typescript, use npx for script execution * prepare v1.8.0 * clean up package, tsconfig * update lib with latest tsc Co-authored-by: Robert Markel --- .env.development | 67 +- .env.production | 45 +- .../AvailabilityContext.d.ts | 14 +- .../AvailabilityPending.d.ts | 6 +- .../AvailabilitySvgComponents.d.ts | 10 +- .../AvailabilityUtils.d.ts | 52 +- .../BasicAvailabilityInterface.d.ts | 26 +- .../BasicAvailabilityKey.d.ts | 10 +- .../EnhancedAvailabilityInterface.d.ts | 18 +- .../EnhancedAvailabilityKey.d.ts | 8 +- lib/components/DialogBase/DialogBase.d.ts | 20 +- .../DownloadDataContext.d.ts | 66 +- .../DownloadDataDialog/DownloadDataDialog.js | 14 +- .../DownloadStepForm/DownloadStepForm.d.ts | 12 +- .../DownloadStepForm/DownloadStepForm.js | 14 +- lib/components/ExternalHost/ExternalHost.d.ts | 10 +- .../ExternalHostProductSpecificLinks.d.ts | 8 +- .../FullWidthVisualization.d.ts | 14 +- .../MaterialTableIcons.d.ts | 34 +- lib/components/NeonApi/NeonApi.d.ts | 34 +- lib/components/NeonApi/NeonApi.js | 2 +- lib/components/NeonAuth/AuthService.d.ts | 15 +- lib/components/NeonAuth/AuthService.js | 16 +- lib/components/NeonAuth/NeonAuth.js | 25 +- lib/components/NeonContext/NeonContext.d.ts | 42 +- lib/components/NeonContext/NeonContext.js | 12 +- .../NeonEnvironment/NeonEnvironment.d.ts | 147 +- .../NeonEnvironment/NeonEnvironment.js | 371 ++- lib/components/NeonEnvironment/package.json | 4 +- lib/components/NeonFooter/NeonFooter.d.ts | 6 +- lib/components/NeonGraphQL/NeonGraphQL.d.ts | 26 +- .../NeonHeader/ApplicationMenu.d.ts | 7 +- lib/components/NeonHeader/ApplicationMenu.js | 18 +- lib/components/NeonHeader/NeonHeader.js | 3 +- lib/components/NeonJsonLd/NeonJsonLd.d.ts | 26 +- .../NeonPage/LiferayNotifications.d.ts | 8 +- lib/components/NeonPage/NeonPage.d.ts | 6 +- lib/components/ReleaseFilter/ReleaseFilter.js | 5 +- lib/components/SiteMap/SiteMapContainer.d.ts | 6 +- lib/components/SiteMap/SiteMapContext.d.ts | 6 +- lib/components/SiteMap/SiteMapContext.js | 33 +- lib/components/SiteMap/SiteMapFeature.d.ts | 6 +- lib/components/SiteMap/SiteMapLeaflet.js | 43 +- lib/components/SiteMap/SiteMapTable.js | 6 +- lib/components/SiteMap/SiteMapUtils.d.ts | 2112 ++++++++++------- lib/components/SiteMap/SiteMapUtils.js | 9 +- lib/components/Theme/Theme.d.ts | 14 +- .../TimeSeriesViewerContainer.js | 6 +- .../TimeSeriesViewerContext.d.ts | 90 +- .../TimeSeriesViewerContext.js | 17 +- .../TimeSeriesViewerDateRange.d.ts | 4 +- .../TimeSeriesViewerSites.d.ts | 24 +- lib/remoteAssets/drupal-header.html.d.ts | 2 +- lib/remoteAssets/drupal-header.html.js | 2 +- lib/remoteAssetsMap/package.json | 2 +- lib/remoteAssetsMap/remoteAssets.d.ts | 16 + lib/remoteAssetsMap/remoteAssets.js | 20 + lib/remoteAssetsMap/remoteAssetsMap.d.ts | 12 +- lib/remoteAssetsMap/remoteAssetsMap.js | 23 +- lib/service/DataCiteService.d.ts | 26 + lib/service/DataCiteService.js | 173 ++ lib/service/RouteService.d.ts | 149 ++ lib/service/RouteService.js | 111 + lib/util/liferayNotificationsUtil.js | 12 +- lib/util/manifestUtil.js | 5 +- package-lock.json | 19 +- package.json | 16 +- public/index.html | 75 +- scripts/lib/lib-cache-remote-assets.js | 34 +- src/components/Home.jsx | 3 +- .../DownloadDataContext.jsx | 12 +- .../DownloadDataDialog/DownloadDataDialog.jsx | 20 +- .../DownloadStepForm/DownloadStepForm.jsx | 11 +- .../__snapshots__/DownloadStepForm.jsx.snap | 8 +- .../components/NeonApi/NeonApi.js | 2 +- .../components/NeonAuth/AuthService.ts | 63 +- .../components/NeonAuth/NeonAuth.tsx | 22 +- .../components/NeonContext/NeonContext.jsx | 14 +- .../NeonEnvironment/NeonEnvironment.js | 288 --- .../NeonEnvironment/NeonEnvironment.ts | 532 +++++ .../__tests__/NeonEnvironment.js | 34 +- .../components/NeonEnvironment/package.json | 4 +- .../components/NeonHeader/ApplicationMenu.tsx | 14 +- .../components/NeonHeader/NeonHeader.jsx | 2 +- .../ReleaseFilter/ReleaseFilter.jsx | 5 +- .../components/SiteMap/SiteMapContext.jsx | 27 +- .../components/SiteMap/SiteMapLeaflet.jsx | 36 +- .../components/SiteMap/SiteMapTable.jsx | 6 +- .../components/SiteMap/SiteMapUtils.js | 8 +- .../components/SiteMap/StyleGuide.jsx | 37 +- .../TimeSeriesViewerContainer.jsx | 5 +- .../TimeSeriesViewerContext.jsx | 24 +- .../TimeSeriesViewerContainer.jsx.snap | 14 +- .../remoteAssets/drupal-header.html.js | 4 + .../remoteAssetsMap/package.json | 2 +- .../remoteAssetsMap/remoteAssets.js | 13 + .../remoteAssetsMap/remoteAssetsMap.js | 21 +- src/lib_components/service/DataCiteService.ts | 224 ++ src/lib_components/service/RouteService.ts | 247 ++ .../util/__tests__/manifestUtil.js | 10 +- .../util/liferayNotificationsUtil.js | 13 +- src/lib_components/util/manifestUtil.ts | 16 +- tsconfig.d.json | 1 + tsconfig.json | 2 +- 104 files changed, 4117 insertions(+), 1921 deletions(-) create mode 100644 lib/remoteAssetsMap/remoteAssets.d.ts create mode 100644 lib/remoteAssetsMap/remoteAssets.js create mode 100644 lib/service/DataCiteService.d.ts create mode 100644 lib/service/DataCiteService.js create mode 100644 lib/service/RouteService.d.ts create mode 100644 lib/service/RouteService.js delete mode 100644 src/lib_components/components/NeonEnvironment/NeonEnvironment.js create mode 100644 src/lib_components/components/NeonEnvironment/NeonEnvironment.ts create mode 100644 src/lib_components/remoteAssetsMap/remoteAssets.js create mode 100644 src/lib_components/service/DataCiteService.ts create mode 100644 src/lib_components/service/RouteService.ts diff --git a/.env.development b/.env.development index 936aedaa..a8098322 100644 --- a/.env.development +++ b/.env.development @@ -1,58 +1,53 @@ PORT=3010 REACT_APP_VERSION=$npm_package_version -REACT_APP_NEON_API_NAME="api" -REACT_APP_NEON_API_VERSION="v0" +#------------------------------------------------------------------------------- +# NEON API root routes +#------------------------------------------------------------------------------- + +REACT_APP_NEON_PATH_API="/api/v0" +REACT_APP_NEON_PATH_PUBLIC_GRAPHQL="/graphql" REACT_APP_NEON_PATH_LD_API="/ld" -REACT_APP_NEON_PATH_LD_REPO_API="/repository" -REACT_APP_NEON_PATH_MENU_API="/menu" -REACT_APP_NEON_PATH_PRODUCTS_API="/products" -REACT_APP_NEON_PATH_RELEASES_API="/releases" -REACT_APP_NEON_PATH_DOCUMENTS_API="/documents" -REACT_APP_NEON_PATH_SITES_API="/sites" -REACT_APP_NEON_PATH_LOCATIONS_API="/locations" -REACT_APP_NEON_PATH_MANIFEST_API="/api/download/v0" +REACT_APP_NEON_PATH_AUTH_API="/api/auth/v0" +REACT_APP_NEON_PATH_AUTH0_API="/auth0" 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" -REACT_APP_NEON_USE_GRAPHQL="true" +#------------------------------------------------------------------------------- +# Application routes +#------------------------------------------------------------------------------- -REACT_APP_NEON_ROUTER_NEON_HOME="/home" -REACT_APP_NEON_ROUTER_NEON_MYACCOUNT="/myaccount" REACT_APP_NEON_ROUTER_BASE="" REACT_APP_NEON_ROUTER_BASE_HOME="/core-components" -REACT_APP_NEON_AUTH_API="/api/auth/v0" -REACT_APP_NEON_AUTH_WS_API="/ws" -REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API="/consumer/topic/auth0" -REACT_APP_NEON_AUTH_LOGIN="/auth0/login" -REACT_APP_NEON_AUTH_LOGOUT="/auth0/logout" -REACT_APP_NEON_AUTH_USERINFO="/auth0/userinfo" +#------------------------------------------------------------------------------- +# Feature options +#------------------------------------------------------------------------------- # Option to disable attempting to connect to the WS # Disabled by default in development as to prevent incessant reconnect attempts REACT_APP_NEON_AUTH_DISABLE_WS="true" - +REACT_APP_NEON_USE_GRAPHQL="true" REACT_APP_NEON_SHOW_AOP_VIEWER="true" + +#------------------------------------------------------------------------------- +# Third party APIs and options +#------------------------------------------------------------------------------- + REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL="https://neon.visus.org/neonapi/products/" REACT_APP_NEON_VISUS_IFRAME_BASE_URL="https://neon.visus.org/visus-frame.html" +REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST="https://api.datacite.org" -# API ROOT -# -# By default API calls made by core components use window.location.host for the root. -# -# This can be overridden using REACT_APP_NEON_HOST_OVERRIDE. Note that the override will -# only be applied in a dev environment. To also apply override in production environments -# set REACT_APP_FOREIGN_LOCATION to "true". +#------------------------------------------------------------------------------- +# Host overrides +#------------------------------------------------------------------------------- + +# The API host can be overridden using REACT_APP_NEON_API_HOST_OVERRIDE. +# Note that the override will only be applied in a dev environment. # # Using portal-core-components as a dependency hosted outside of data.neonscience.org: # * Set REACT_APP_NEON_HOST_OVERRIDE to "https://data.neonscience.org" -# * Set REACT_APP_FOREIGN_LOCATION to "true" -# Rate limiting may apply. See https://data.neonscience.org/data-api/rate-limiting/ for details. +# Rate limiting may apply. +# See https://data.neonscience.org/data-api/rate-limiting/ for details. -REACT_APP_NEON_HOST_OVERRIDE="https://int-data.neonscience.org" -# REACT_APP_FOREIGN_LOCATION="true" +REACT_APP_NEON_API_HOST_OVERRIDE="https://int-data.neonscience.org" +REACT_APP_NEON_WEB_HOST_OVERRIDE="https://www.neonscience.org" diff --git a/.env.production b/.env.production index 31561396..c85fef3c 100644 --- a/.env.production +++ b/.env.production @@ -1,37 +1,34 @@ REACT_APP_VERSION=$npm_package_version -REACT_APP_NEON_API_NAME="api" -REACT_APP_NEON_API_VERSION="v0" +#------------------------------------------------------------------------------- +# NEON API root routes +#------------------------------------------------------------------------------- + +REACT_APP_NEON_PATH_API="/api/v0" +REACT_APP_NEON_PATH_PUBLIC_GRAPHQL="/graphql" REACT_APP_NEON_PATH_LD_API="/ld" -REACT_APP_NEON_PATH_LD_REPO_API="/repository" -REACT_APP_NEON_PATH_MENU_API="/menu" -REACT_APP_NEON_PATH_PRODUCTS_API="/products" -REACT_APP_NEON_PATH_RELEASES_API="/releases" -REACT_APP_NEON_PATH_DOCUMENTS_API="/documents" -REACT_APP_NEON_PATH_SITES_API="/sites" -REACT_APP_NEON_PATH_LOCATIONS_API="/locations" -REACT_APP_NEON_PATH_MANIFEST_API="/api/download/v0" +REACT_APP_NEON_PATH_AUTH_API="/api/auth/v0" +REACT_APP_NEON_PATH_AUTH0_API="/auth0" 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" -REACT_APP_NEON_USE_GRAPHQL="true" +#------------------------------------------------------------------------------- +# Application routes +#------------------------------------------------------------------------------- -REACT_APP_NEON_ROUTER_NEON_HOME="/home" -REACT_APP_NEON_ROUTER_NEON_MYACCOUNT="/myaccount" REACT_APP_NEON_ROUTER_BASE="" REACT_APP_NEON_ROUTER_BASE_HOME="/core-components" -REACT_APP_NEON_AUTH_API="/api/auth/v0" -REACT_APP_NEON_AUTH_WS_API="/ws" -REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API="/consumer/topic/auth0" -REACT_APP_NEON_AUTH_LOGIN="/auth0/login" -REACT_APP_NEON_AUTH_LOGOUT="/auth0/logout" -REACT_APP_NEON_AUTH_USERINFO="/auth0/userinfo" +#------------------------------------------------------------------------------- +# Feature options +#------------------------------------------------------------------------------- +REACT_APP_NEON_USE_GRAPHQL="true" REACT_APP_NEON_SHOW_AOP_VIEWER="true" + +#------------------------------------------------------------------------------- +# Third party APIs and options +#------------------------------------------------------------------------------- + REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL="https://neon.visus.org/neonapi/products/" REACT_APP_NEON_VISUS_IFRAME_BASE_URL="https://neon.visus.org/visus-frame.html" +REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST="https://api.datacite.org" diff --git a/lib/components/DataProductAvailability/AvailabilityContext.d.ts b/lib/components/DataProductAvailability/AvailabilityContext.d.ts index 349ad33f..60f50f8b 100644 --- a/lib/components/DataProductAvailability/AvailabilityContext.d.ts +++ b/lib/components/DataProductAvailability/AvailabilityContext.d.ts @@ -37,21 +37,21 @@ declare namespace AvailabilityContext { */ declare function Provider(props: any): JSX.Element; declare namespace Provider { - export namespace propTypes { - export const sites: PropTypes.Requireable<(PropTypes.InferProps<{ + namespace propTypes { + const sites: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; tables: PropTypes.Validator<(PropTypes.InferProps<{ name: PropTypes.Validator; description: PropTypes.Validator; waitInterval: PropTypes.Validator; months: PropTypes.Validator<{ - [x: string]: import("../../types/core").Nullable; + [x: string]: string | null | undefined; }>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const children: PropTypes.Validator; + const children: PropTypes.Validator; } - export namespace defaultProps { + namespace defaultProps { const sites_1: never[]; export { sites_1 as sites }; } @@ -73,7 +73,7 @@ declare function useAvailabilityState(): any[] | { }; }; declare namespace SORT_DIRECTIONS { - export const ASC: string; - export const DESC: string; + const ASC: string; + const DESC: string; } import PropTypes from "prop-types"; diff --git a/lib/components/DataProductAvailability/AvailabilityPending.d.ts b/lib/components/DataProductAvailability/AvailabilityPending.d.ts index 83f6ed27..9fecb278 100644 --- a/lib/components/DataProductAvailability/AvailabilityPending.d.ts +++ b/lib/components/DataProductAvailability/AvailabilityPending.d.ts @@ -1,9 +1,9 @@ declare function AvailabilityPending(props: any): JSX.Element | null; declare namespace AvailabilityPending { - export namespace propTypes { - export const message: PropTypes.Requireable; + namespace propTypes { + const message: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const message_1: string; export { message_1 as message }; } diff --git a/lib/components/DataProductAvailability/AvailabilitySvgComponents.d.ts b/lib/components/DataProductAvailability/AvailabilitySvgComponents.d.ts index 87a16740..e188653b 100644 --- a/lib/components/DataProductAvailability/AvailabilitySvgComponents.d.ts +++ b/lib/components/DataProductAvailability/AvailabilitySvgComponents.d.ts @@ -102,12 +102,12 @@ export const CELL_ATTRS: { }; export function JsxCell(props: any): JSX.Element; export namespace JsxCell { - export namespace propTypes { - export const status: PropTypes.Validator; - export const x: PropTypes.Requireable; - export const y: PropTypes.Requireable; + namespace propTypes { + const status: PropTypes.Validator; + const x: PropTypes.Requireable; + const y: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const x_1: number; export { x_1 as x }; const y_1: number; diff --git a/lib/components/DataProductAvailability/AvailabilityUtils.d.ts b/lib/components/DataProductAvailability/AvailabilityUtils.d.ts index 351b3e9d..72bfeadb 100644 --- a/lib/components/DataProductAvailability/AvailabilityUtils.d.ts +++ b/lib/components/DataProductAvailability/AvailabilityUtils.d.ts @@ -49,51 +49,63 @@ export const VALID_ENHANCED_STATUSES: { }; export function calcRollupStatus(statuses?: any[]): any; export namespace AvailabilityPropTypes { - export const basicSiteCodes: PropTypes.Requireable<(PropTypes.InferProps<{ + const basicSiteCodes: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; availableReleases: PropTypes.Requireable<(PropTypes.InferProps<{ release: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const enhancedSites: PropTypes.Requireable<(PropTypes.InferProps<{ + const enhancedSites: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; tables: PropTypes.Validator<(PropTypes.InferProps<{ name: PropTypes.Validator; description: PropTypes.Validator; waitInterval: PropTypes.Validator; months: PropTypes.Validator<{ - [x: string]: import("../../types/core").Nullable; + [x: string]: string | null | undefined; }>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const dataProducts: PropTypes.Requireable<(PropTypes.InferProps<{ + const dataProducts: PropTypes.Requireable<(PropTypes.InferProps<{ dataProductCode: PropTypes.Validator; dataProductTitle: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; availableReleases: PropTypes.Requireable<(PropTypes.InferProps<{ release: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; }> | null | undefined)[]>; }> | null | undefined)[]>; } export namespace SVG { - export const MIN_WIDTH: number; - export const MIN_HEIGHT: number; - export const YEAR_MONTH_WIDTH: number; - export const YEAR_WIDTH: number; - export const ABS_MAX_DATA_WIDTH: number; + const MIN_WIDTH: number; + const MIN_HEIGHT: number; + const YEAR_MONTH_WIDTH: number; + const YEAR_WIDTH: number; + const ABS_MAX_DATA_WIDTH: number; } export namespace TIME { - export const MIN_YEAR_MONTH: string; - export const MAX_YEAR_MONTH: string; - export const YEARS: number[]; - export const MONTHS: string[]; - export const YEAR_MONTHS: any; + const MIN_YEAR_MONTH: string; + const MAX_YEAR_MONTH: string; + const YEARS: number[]; + const MONTHS: string[]; + const YEAR_MONTHS: any; } export namespace SVG_STYLES { - export function apply(node: any, styleName: any): void; - export function touchRipple(selection: any, duration?: number): void; + /** + Function: apply + Parse an object literal style definition into d3 selection.style() + calls to apply styles defined in the styles object literal to a node + */ + function apply(node: any, styleName: any): void; + /** + Function: touchRipple + For click interactions pass a d3 selection in and the fill will transition + from an "active" semi-transparent orange color to near-transparent. We don't go + full transparent as the ripple is typically followed by a delayed state update + that will trigger a rerender and thus a full style reset. + */ + function touchRipple(selection: any, duration?: number): void; } import PropTypes from "prop-types"; diff --git a/lib/components/DataProductAvailability/BasicAvailabilityInterface.d.ts b/lib/components/DataProductAvailability/BasicAvailabilityInterface.d.ts index 809c0be3..47efd180 100644 --- a/lib/components/DataProductAvailability/BasicAvailabilityInterface.d.ts +++ b/lib/components/DataProductAvailability/BasicAvailabilityInterface.d.ts @@ -4,31 +4,31 @@ export default BasicAvailabilityInterface; */ declare function BasicAvailabilityInterface(props: any): JSX.Element; declare namespace BasicAvailabilityInterface { - export namespace propTypes { - export const siteCodes: PropTypes.Requireable<(PropTypes.InferProps<{ + namespace propTypes { + const siteCodes: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; availableReleases: PropTypes.Requireable<(PropTypes.InferProps<{ release: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const dataProducts: PropTypes.Requireable<(PropTypes.InferProps<{ + const dataProducts: PropTypes.Requireable<(PropTypes.InferProps<{ dataProductCode: PropTypes.Validator; dataProductTitle: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; availableReleases: PropTypes.Requireable<(PropTypes.InferProps<{ release: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const view: PropTypes.Requireable; - export const sortMethod: PropTypes.Requireable; - export const sortDirection: PropTypes.Requireable; - export const disableSelection: PropTypes.Requireable; - export const delineateRelease: PropTypes.Requireable; + const view: PropTypes.Requireable; + const sortMethod: PropTypes.Requireable; + const sortDirection: PropTypes.Requireable; + const disableSelection: PropTypes.Requireable; + const delineateRelease: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const siteCodes_1: never[]; export { siteCodes_1 as siteCodes }; const dataProducts_1: never[]; diff --git a/lib/components/DataProductAvailability/BasicAvailabilityKey.d.ts b/lib/components/DataProductAvailability/BasicAvailabilityKey.d.ts index 330ce62e..f3aa22ef 100644 --- a/lib/components/DataProductAvailability/BasicAvailabilityKey.d.ts +++ b/lib/components/DataProductAvailability/BasicAvailabilityKey.d.ts @@ -3,12 +3,12 @@ */ declare function BasicAvailabilityKey(props: any): JSX.Element; declare namespace BasicAvailabilityKey { - export namespace propTypes { - export const orientation: PropTypes.Requireable; - export const selectionEnabled: PropTypes.Requireable; - export const delineateRelease: PropTypes.Requireable; + namespace propTypes { + const orientation: PropTypes.Requireable; + const selectionEnabled: PropTypes.Requireable; + const delineateRelease: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const orientation_1: string; export { orientation_1 as orientation }; const selectionEnabled_1: boolean; diff --git a/lib/components/DataProductAvailability/EnhancedAvailabilityInterface.d.ts b/lib/components/DataProductAvailability/EnhancedAvailabilityInterface.d.ts index 73e55626..a00b5856 100644 --- a/lib/components/DataProductAvailability/EnhancedAvailabilityInterface.d.ts +++ b/lib/components/DataProductAvailability/EnhancedAvailabilityInterface.d.ts @@ -1,8 +1,8 @@ export default EnhancedAvailabilityInterface; declare function EnhancedAvailabilityInterface(props: any): JSX.Element; declare namespace EnhancedAvailabilityInterface { - export namespace propTypes { - export const sites: PropTypes.Requireable<(PropTypes.InferProps<{ + namespace propTypes { + const sites: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; tables: PropTypes.Validator<(PropTypes.InferProps<{ name: PropTypes.Validator; @@ -11,17 +11,17 @@ declare namespace EnhancedAvailabilityInterface { */ waitInterval: PropTypes.Validator; months: PropTypes.Validator<{ - [x: string]: import("../../types/core").Nullable; + [x: string]: string | null | undefined; }>; }> | null | undefined)[]>; }> | null | undefined)[]>; - export const view: PropTypes.Requireable; - export const table: PropTypes.Requireable; - export const sortMethod: PropTypes.Requireable; - export const sortDirection: PropTypes.Requireable; - export const disableSelection: PropTypes.Requireable; + const view: PropTypes.Requireable; + const table: PropTypes.Requireable; + const sortMethod: PropTypes.Requireable; + const sortDirection: PropTypes.Requireable; + const disableSelection: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const sites_1: never[]; export { sites_1 as sites }; const view_1: null; diff --git a/lib/components/DataProductAvailability/EnhancedAvailabilityKey.d.ts b/lib/components/DataProductAvailability/EnhancedAvailabilityKey.d.ts index 1c12fe51..f19a70cf 100644 --- a/lib/components/DataProductAvailability/EnhancedAvailabilityKey.d.ts +++ b/lib/components/DataProductAvailability/EnhancedAvailabilityKey.d.ts @@ -3,11 +3,11 @@ */ declare function EnhancedAvailabilityKey(props: any): JSX.Element; declare namespace EnhancedAvailabilityKey { - export namespace propTypes { - export const selectionEnabled: PropTypes.Requireable; - export const rollUpPresent: PropTypes.Requireable; + namespace propTypes { + const selectionEnabled: PropTypes.Requireable; + const rollUpPresent: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const selectionEnabled_1: boolean; export { selectionEnabled_1 as selectionEnabled }; const rollUpPresent_1: boolean; diff --git a/lib/components/DialogBase/DialogBase.d.ts b/lib/components/DialogBase/DialogBase.d.ts index a51f376a..53ff5062 100644 --- a/lib/components/DialogBase/DialogBase.d.ts +++ b/lib/components/DialogBase/DialogBase.d.ts @@ -1,19 +1,19 @@ export default DialogBase; declare function DialogBase(props: any): JSX.Element; declare namespace DialogBase { - export namespace propTypes { - export const open: PropTypes.Requireable; - export const onClose: PropTypes.Validator<(...args: any[]) => any>; - export const title: PropTypes.Validator; - export const toolbarChildren: PropTypes.Requireable; - export const children: PropTypes.Validator; - export const closeButtonProps: PropTypes.Requireable<{ + namespace propTypes { + const open: PropTypes.Requireable; + const onClose: PropTypes.Validator<(...args: any[]) => any>; + const title: PropTypes.Validator; + const toolbarChildren: PropTypes.Requireable; + const children: PropTypes.Validator; + const closeButtonProps: PropTypes.Requireable<{ [x: string]: string | number | null | undefined; }>; - export const nopaper: PropTypes.Requireable; - export const style: PropTypes.Requireable; + const nopaper: PropTypes.Requireable; + const style: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const open_1: boolean; export { open_1 as open }; const toolbarChildren_1: null; diff --git a/lib/components/DownloadDataContext/DownloadDataContext.d.ts b/lib/components/DownloadDataContext/DownloadDataContext.d.ts index 67c92088..e548e15f 100644 --- a/lib/components/DownloadDataContext/DownloadDataContext.d.ts +++ b/lib/components/DownloadDataContext/DownloadDataContext.d.ts @@ -120,30 +120,30 @@ declare namespace DownloadDataContext { */ declare function Provider(props: any): JSX.Element; declare namespace Provider { - export namespace propTypes { - export const stateObservable: PropTypes.Requireable<(...args: any[]) => any>; - export const productData: PropTypes.Requireable any>; + const productData: PropTypes.Requireable; productName: PropTypes.Validator; siteCodes: PropTypes.Requireable<(PropTypes.InferProps<{ siteCode: PropTypes.Validator; - availableMonths: PropTypes.Validator[]>; + availableMonths: PropTypes.Validator<(string | null | undefined)[]>; }> | null | undefined)[]>; }>>; - export const availabilityView: PropTypes.Requireable; - export const release: PropTypes.Requireable; - export const sites: PropTypes.Requireable[]>; - export const dateRange: PropTypes.Requireable[]>; - export const documentation: PropTypes.Requireable; - export const packageType: PropTypes.Requireable; - export const children: PropTypes.Validator; + const availabilityView: PropTypes.Requireable; + const release: PropTypes.Requireable; + const sites: PropTypes.Requireable<(string | null | undefined)[]>; + const dateRange: PropTypes.Requireable<(string | null | undefined)[]>; + const documentation: PropTypes.Requireable; + const packageType: PropTypes.Requireable; + const children: PropTypes.Validator; } - export namespace defaultProps { + namespace defaultProps { const stateObservable_1: null; export { stateObservable_1 as stateObservable }; const productData_1: {}; export { productData_1 as productData }; - import availabilityView_1 = availabilityView; + import availabilityView_1 = DEFAULT_STATE.availabilityView; export { availabilityView_1 as availabilityView }; import release_1 = value; export { release_1 as release }; @@ -329,9 +329,9 @@ declare namespace DEFAULT_STATE { export const fromAOPManifest: boolean; export const fromExternalHost: boolean; export namespace manifest { - export const status: string; - export const value: null; - export const error: null; + const status: string; + const value: null; + const error: null; } const availabilityView_2: null; export { availabilityView_2 as availabilityView }; @@ -348,18 +348,22 @@ declare namespace DEFAULT_STATE { export const estimatedPostSize: number; export const filteredFileCount: number; export const lastFilterChanged: null; - export const filters: { - site: never[]; - type: never[]; - visit: never[]; - yearMonth: never[]; - }; - export const valueLookups: { - site: {}; - type: {}; - visit: {}; - yearMonth: {}; - }; + export namespace filters { + const site: never[]; + const type: never[]; + const visit: never[]; + const yearMonth: never[]; + } + export namespace valueLookups { + const site_1: {}; + export { site_1 as site }; + const type_1: {}; + export { type_1 as type }; + const visit_1: {}; + export { visit_1 as visit }; + const yearMonth_1: {}; + export { yearMonth_1 as yearMonth }; + } export const visibleColumns: string[]; } export const latestRelease: null; @@ -419,9 +423,9 @@ declare namespace DEFAULT_STATE { } declare namespace ALL_STEPS { export namespace documentation_3 { - export const requiredStateKeys: string[]; - export const label: string; - export const title: string; + const requiredStateKeys: string[]; + const label: string; + const title: string; } export { documentation_3 as documentation }; export namespace externalExclusive { diff --git a/lib/components/DownloadDataDialog/DownloadDataDialog.js b/lib/components/DownloadDataDialog/DownloadDataDialog.js index 3aaf1978..c0ca4092 100644 --- a/lib/components/DownloadDataDialog/DownloadDataDialog.js +++ b/lib/components/DownloadDataDialog/DownloadDataDialog.js @@ -79,6 +79,8 @@ var _NeonEnvironment = _interopRequireDefault(require("../NeonEnvironment/NeonEn var _Theme = _interopRequireWildcard(require("../Theme/Theme")); +var _RouteService = _interopRequireDefault(require("../../service/RouteService")); + var _manifestUtil = require("../../util/manifestUtil"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -419,14 +421,6 @@ function DownloadDataDialog() { } var formattedBytes = (0, _manifestUtil.formatBytes)(bytes); - - var aopHardDriveLink = /*#__PURE__*/_react.default.createElement(_Link.default, { - target: "_blank", - href: "https://www.neonscience.org/data-collection/airborne-remote-sensing/aop-data-hard-drive-request" - }, "AOP Data to Hard Drive Request"); - - var aopBlurb = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "An alternate way to obtain lots of AOP data is to submit an ", aopHardDriveLink, "."); - return /*#__PURE__*/_react.default.createElement(_Card.default, { className: classes.callout }, /*#__PURE__*/_react.default.createElement(_CardContent.default, { @@ -441,7 +435,7 @@ function DownloadDataDialog() { } }, "Be sure you have at least ", formattedBytes, " of free disk space for this download!"), /*#__PURE__*/_react.default.createElement(_Typography.default, { variant: "body1" - }, "If needed, you can reduce the download size by selecting fewer sites or a more restrictive date range. ", fromAOPManifest ? aopBlurb : null)))); + }, "If needed, you can reduce the download size by selecting fewer sites or a more restrictive date range.")))); }; var renderFileType = function renderFileType() { @@ -530,7 +524,7 @@ function DownloadDataDialog() { var benefitsLink = /*#__PURE__*/_react.default.createElement(_Link.default, { target: "_new", - href: "https://www.neonscience.org/about/user-accounts" + href: _RouteService.default.getUserAccountsPath() }, "here"); /* eslint-disable react/jsx-one-expression-per-line */ diff --git a/lib/components/DownloadStepForm/DownloadStepForm.d.ts b/lib/components/DownloadStepForm/DownloadStepForm.d.ts index c20d173e..977bc0e4 100644 --- a/lib/components/DownloadStepForm/DownloadStepForm.d.ts +++ b/lib/components/DownloadStepForm/DownloadStepForm.d.ts @@ -1,12 +1,12 @@ declare function DownloadStepForm(props: any): any; declare namespace DownloadStepForm { - export namespace propTypes { - export const stepKey: PropTypes.Validator; - export const changeToStep: PropTypes.Requireable<(...args: any[]) => any>; - export const changeToNextUncompletedStep: PropTypes.Requireable<(...args: any[]) => any>; - export const renderDownloadButton: PropTypes.Requireable<(...args: any[]) => any>; + namespace propTypes { + const stepKey: PropTypes.Validator; + const changeToStep: PropTypes.Requireable<(...args: any[]) => any>; + const changeToNextUncompletedStep: PropTypes.Requireable<(...args: any[]) => any>; + const renderDownloadButton: PropTypes.Requireable<(...args: any[]) => any>; } - export namespace defaultProps { + namespace defaultProps { export function changeToStep_1(): void; export { changeToStep_1 as changeToStep }; export function changeToNextUncompletedStep_1(): void; diff --git a/lib/components/DownloadStepForm/DownloadStepForm.js b/lib/components/DownloadStepForm/DownloadStepForm.js index 07e7c2de..8f4172f8 100644 --- a/lib/components/DownloadStepForm/DownloadStepForm.js +++ b/lib/components/DownloadStepForm/DownloadStepForm.js @@ -89,6 +89,8 @@ var _SiteChip = _interopRequireDefault(require("../SiteChip/SiteChip")); var _Theme = _interopRequireWildcard(require("../Theme/Theme")); +var _RouteService = _interopRequireDefault(require("../../service/RouteService")); + var _manifestUtil = require("../../util/manifestUtil"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -209,7 +211,7 @@ var useStyles = (0, _styles.makeStyles)(function (theme) { var dataUsageAndCitationPoliciesLink = /*#__PURE__*/_react.default.createElement(_Link.default, { target: "_blank", - href: "https://www.neonscience.org/data/about-data/data-policies", + href: _RouteService.default.getDataPoliciesPath(), "data-gtm": "download-data-dialog.policies-link" }, "Data Usage and Citation Policies"); @@ -312,7 +314,7 @@ function DownloadStepForm(props) { documentation: function documentation() { var neonFaqLink = /*#__PURE__*/_react.default.createElement(_Link.default, { target: "_blank", - href: "http://data.neonscience.org/faq", + href: _RouteService.default.getFaqPath(), "data-gtm": "download-data-dialog.neon-faq-link" }, "NEON FAQ"); @@ -853,7 +855,7 @@ function DownloadStepForm(props) { var downloadAndExploreLink = /*#__PURE__*/_react.default.createElement(_Link.default, { target: "_blank", - href: "https://www.neonscience.org/download-explore-neon-data", + href: _RouteService.default.getDownloadExplorePath(), "data-gtm": "download-data-dialog.download-and-explore-link" }, "Download and Explore NEON Data"); @@ -873,7 +875,7 @@ function DownloadStepForm(props) { var fileNamingConventionsLink = /*#__PURE__*/_react.default.createElement(_Link.default, { target: "_blank", - href: "https://data.neonscience.org/file-naming-conventions", + href: _RouteService.default.getFileNamingConventionsPath(), "data-gtm": "download-data-dialog.file-naming-conventions-link" }, "NEON File Naming Conventions"); @@ -897,7 +899,9 @@ function DownloadStepForm(props) { var year = (0, _moment.default)().format('YYYY'); var today = (0, _moment.default)().format('MMMM D, YYYY'); var maturity = 'Provisional'; - var url = 'http://data.neonscience.org'; + + var url = _RouteService.default.getDataProductCitationDownloadUrl(); + var citationText = "National Ecological Observatory Network. ".concat(year, ". Data Product ").concat(productCode, ", ").concat(productName, ". ").concat(maturity, " data downloaded from ").concat(url, " on ").concat(today, ". Battelle, Boulder, CO, USA NEON. ").concat(year, "."); var citationCallout = /*#__PURE__*/_react.default.createElement(_Card.default, { diff --git a/lib/components/ExternalHost/ExternalHost.d.ts b/lib/components/ExternalHost/ExternalHost.d.ts index fe304f12..07765cc8 100644 --- a/lib/components/ExternalHost/ExternalHost.d.ts +++ b/lib/components/ExternalHost/ExternalHost.d.ts @@ -7,13 +7,13 @@ declare namespace ExternalHost { export { renderExternalHostLink }; } declare namespace HOST_TYPES { - export const ADDITIONAL_DATA: string; - export const REFORMATTED_DATA: string; - export const EXCLUSIVE_DATA: string; + const ADDITIONAL_DATA: string; + const REFORMATTED_DATA: string; + const EXCLUSIVE_DATA: string; } declare namespace LINK_TYPES { - export const BY_SITE: string; - export const BY_PRODUCT: string; + const BY_SITE: string; + const BY_PRODUCT: string; } declare function getByHostId(hostId?: string): any; declare function getByProductCode(productCode?: string): any; diff --git a/lib/components/ExternalHostProductSpecificLinks/ExternalHostProductSpecificLinks.d.ts b/lib/components/ExternalHostProductSpecificLinks/ExternalHostProductSpecificLinks.d.ts index 2130d382..d82b338b 100644 --- a/lib/components/ExternalHostProductSpecificLinks/ExternalHostProductSpecificLinks.d.ts +++ b/lib/components/ExternalHostProductSpecificLinks/ExternalHostProductSpecificLinks.d.ts @@ -1,10 +1,10 @@ declare function ExternalHostProductSpecificLinks(props: any): JSX.Element | null; declare namespace ExternalHostProductSpecificLinks { - export namespace propTypes { - export const productCode: PropTypes.Requireable; - export const siteCodes: PropTypes.Requireable[]>; + namespace propTypes { + const productCode: PropTypes.Requireable; + const siteCodes: PropTypes.Requireable<(string | null | undefined)[]>; } - export namespace defaultProps { + namespace defaultProps { const productCode_1: null; export { productCode_1 as productCode }; const siteCodes_1: null; diff --git a/lib/components/FullWidthVisualization/FullWidthVisualization.d.ts b/lib/components/FullWidthVisualization/FullWidthVisualization.d.ts index 4698bea4..8a2eac24 100644 --- a/lib/components/FullWidthVisualization/FullWidthVisualization.d.ts +++ b/lib/components/FullWidthVisualization/FullWidthVisualization.d.ts @@ -1,15 +1,15 @@ declare function FullWidthVisualization(props: any): JSX.Element; declare namespace FullWidthVisualization { - export namespace propTypes { - export const vizRef: PropTypes.Validator; }>>; - export const minWidth: PropTypes.Requireable; - export const handleRedraw: PropTypes.Requireable<(...args: any[]) => any>; - export const deriveHeightFromWidth: PropTypes.Requireable any)>; - export const children: PropTypes.Validator; + const minWidth: PropTypes.Requireable; + const handleRedraw: PropTypes.Requireable<(...args: any[]) => any>; + const deriveHeightFromWidth: PropTypes.Requireable any)>; + const children: PropTypes.Validator; } - export namespace defaultProps { + namespace defaultProps { const minWidth_1: number; export { minWidth_1 as minWidth }; const handleRedraw_1: null; diff --git a/lib/components/MaterialTableIcons/MaterialTableIcons.d.ts b/lib/components/MaterialTableIcons/MaterialTableIcons.d.ts index 36b73c6d..5111f451 100644 --- a/lib/components/MaterialTableIcons/MaterialTableIcons.d.ts +++ b/lib/components/MaterialTableIcons/MaterialTableIcons.d.ts @@ -1,21 +1,21 @@ export default MaterialTableIcons; declare namespace MaterialTableIcons { - export const Add: React.ForwardRefExoticComponent>; - export const Check: React.ForwardRefExoticComponent>; - export const Clear: React.ForwardRefExoticComponent>; - export const Delete: React.ForwardRefExoticComponent>; - export const DetailPanel: React.ForwardRefExoticComponent>; - export const Edit: React.ForwardRefExoticComponent>; - export const Export: React.ForwardRefExoticComponent>; - export const Filter: React.ForwardRefExoticComponent>; - export const FirstPage: React.ForwardRefExoticComponent>; - export const LastPage: React.ForwardRefExoticComponent>; - export const NextPage: React.ForwardRefExoticComponent>; - export const PreviousPage: React.ForwardRefExoticComponent>; - export const ResetSearch: React.ForwardRefExoticComponent>; - export const Search: React.ForwardRefExoticComponent>; - export const SortArrow: React.ForwardRefExoticComponent>; - export const ThirdStateCheck: React.ForwardRefExoticComponent>; - export const ViewColumn: React.ForwardRefExoticComponent>; + const Add: React.ForwardRefExoticComponent>; + const Check: React.ForwardRefExoticComponent>; + const Clear: React.ForwardRefExoticComponent>; + const Delete: React.ForwardRefExoticComponent>; + const DetailPanel: React.ForwardRefExoticComponent>; + const Edit: React.ForwardRefExoticComponent>; + const Export: React.ForwardRefExoticComponent>; + const Filter: React.ForwardRefExoticComponent>; + const FirstPage: React.ForwardRefExoticComponent>; + const LastPage: React.ForwardRefExoticComponent>; + const NextPage: React.ForwardRefExoticComponent>; + const PreviousPage: React.ForwardRefExoticComponent>; + const ResetSearch: React.ForwardRefExoticComponent>; + const Search: React.ForwardRefExoticComponent>; + const SortArrow: React.ForwardRefExoticComponent>; + const ThirdStateCheck: React.ForwardRefExoticComponent>; + const ViewColumn: React.ForwardRefExoticComponent>; } import React from "react"; diff --git a/lib/components/NeonApi/NeonApi.d.ts b/lib/components/NeonApi/NeonApi.d.ts index 3923462c..fff4e712 100644 --- a/lib/components/NeonApi/NeonApi.d.ts +++ b/lib/components/NeonApi/NeonApi.d.ts @@ -9,21 +9,21 @@ export function getTestableItems(): { postJsonObservable: (url: string, body: any, headers?: Object | undefined, includeToken?: boolean) => import("rxjs").Observable | import("rxjs").Observable; }; declare namespace NeonApi { - export function getApiTokenHeader(headers?: Object | undefined): Object; - export function getJsonObservable(url: string, headers?: Object | undefined, includeToken?: boolean): import("rxjs").Observable; - export function postJsonObservable(url: string, body: any, headers?: Object | undefined, includeToken?: boolean): import("rxjs").Observable | import("rxjs").Observable; - export function getJson(url: string, callback: any, errorCallback: any, cancellationSubject$: any, headers?: Object | undefined): import("rxjs").Subscription; - export function getProductsObservable(): import("rxjs").Observable; - export function getProductObservable(productCode: string, release?: string): import("rxjs").Observable; - export function getPrototypeDatasetsObservable(): import("rxjs").Observable; - export function getPrototypeDatasetObservable(uuid: any): import("rxjs").Observable; - export function getPrototypeManifestRollupObservable(uuid: any): import("rxjs").Observable; - export function getPrototypeDataFileObservable(uuid: any, fileName: any): import("rxjs").Observable; - export function getReleasesObservable(): import("rxjs").Observable; - export function getReleaseObservable(release: string): import("rxjs").Observable; - export function getSitesJsonObservable(): import("rxjs").Observable; - export function getSiteJsonObservable(siteCode: string): import("rxjs").Observable; - export function getSiteLocationHierarchyObservable(siteCode: string): import("rxjs").Observable; - export function getLocationObservable(location: string): import("rxjs").Observable; - export function getArcgisAssetObservable(feature: string, siteCode: string): import("rxjs").Observable; + function getApiTokenHeader(headers?: Object | undefined): Object; + function getJsonObservable(url: string, headers?: Object | undefined, includeToken?: boolean): import("rxjs").Observable; + function postJsonObservable(url: string, body: any, headers?: Object | undefined, includeToken?: boolean): import("rxjs").Observable | import("rxjs").Observable; + function getJson(url: string, callback: any, errorCallback: any, cancellationSubject$: any, headers?: Object | undefined): import("rxjs").Subscription; + function getProductsObservable(): import("rxjs").Observable; + function getProductObservable(productCode: string, release?: string): import("rxjs").Observable; + function getPrototypeDatasetsObservable(): import("rxjs").Observable; + function getPrototypeDatasetObservable(uuid: any): import("rxjs").Observable; + function getPrototypeManifestRollupObservable(uuid: any): import("rxjs").Observable; + function getPrototypeDataFileObservable(uuid: any, fileName: any): import("rxjs").Observable; + function getReleasesObservable(): import("rxjs").Observable; + function getReleaseObservable(release: string): import("rxjs").Observable; + function getSitesJsonObservable(): import("rxjs").Observable; + function getSiteJsonObservable(siteCode: string): import("rxjs").Observable; + function getSiteLocationHierarchyObservable(siteCode: string): import("rxjs").Observable; + function getLocationObservable(location: string): import("rxjs").Observable; + function getArcgisAssetObservable(feature: string, siteCode: string): import("rxjs").Observable; } diff --git a/lib/components/NeonApi/NeonApi.js b/lib/components/NeonApi/NeonApi.js index 188ec43b..36579511 100644 --- a/lib/components/NeonApi/NeonApi.js +++ b/lib/components/NeonApi/NeonApi.js @@ -198,7 +198,7 @@ var NeonApi = { }, getPrototypeManifestRollupObservable: function getPrototypeManifestRollupObservable(uuid) { return (// eslint-disable-next-line max-len - _getJsonObservable("".concat(_NeonEnvironment.default.getFullApiPath('manifest'), "/prototype/manifest/rollup?uuid=").concat(uuid)) + _getJsonObservable("".concat(_NeonEnvironment.default.getFullDownloadApiPath('prototypeManifestRollup'), "?uuid=").concat(uuid)) ); }, getPrototypeDataFileObservable: function getPrototypeDataFileObservable(uuid, fileName) { diff --git a/lib/components/NeonAuth/AuthService.d.ts b/lib/components/NeonAuth/AuthService.d.ts index 378e4513..cca180ab 100644 --- a/lib/components/NeonAuth/AuthService.d.ts +++ b/lib/components/NeonAuth/AuthService.d.ts @@ -34,14 +34,19 @@ export interface IAuthService { /** * Initializes a login flow * @param {string} path - Optionally path to set for the root login URL + * @param {string} redirectUriPath - Optionally set the redirect path */ - login: (path?: string) => void; + login: (path?: string, redirectUriPath?: string) => void; /** * Performs a silent login flow * @param {Dispatch} dispatch - The NeonContext dispatch function * @param {boolean} isSsoCheck - Whether or not performaing an SSO check + * @param {string} path - Fallback to optionally path to set for the + * root logout URL when defaulting to normal login flow. + * @param {string} redirectUriPath - Fallback to optionally set the + * redirect path when defaulting to normal login flow. */ - loginSilently: (dispatch: Dispatch, isSsoCheck: boolean) => void; + loginSilently: (dispatch: Dispatch, isSsoCheck: boolean, path?: string, redirectUriPath?: string) => void; /** * Initializes a logout flow * @param {string} path - Optionally path to set for the root logout URL @@ -52,8 +57,12 @@ export interface IAuthService { * Performs a silent logout flow * @param {Dispatch} dispatch - The NeonContext dispatch function * upon logout + * @param {string} path - Fallback to optionally path to set for the + * root logout URL when defaulting to normal login flow. + * @param {string} redirectUriPath - Fallback to optionally set the + * redirect path when defaulting to normal login flow. */ - logoutSilently: (dispatch: Dispatch) => void; + logoutSilently: (dispatch: Dispatch, path?: string, redirectUriPath?: string) => void; /** * Cancels the user info request */ diff --git a/lib/components/NeonAuth/AuthService.js b/lib/components/NeonAuth/AuthService.js index 8d8f50ac..ff1ea2d2 100644 --- a/lib/components/NeonAuth/AuthService.js +++ b/lib/components/NeonAuth/AuthService.js @@ -167,14 +167,14 @@ var AuthService = { isAuthOnlyApp: function isAuthOnlyApp() { return [_NeonEnvironment.default.route.account()].indexOf(_NeonEnvironment.default.getRouterBaseHomePath() || '') >= 0; }, - login: function login(path) { + login: function login(path, redirectUriPath) { var env = _NeonEnvironment.default; var rootPath = (0, _typeUtil.exists)(path) ? path : env.getFullAuthPath('login'); - var redirectUri = "".concat(env.route.getFullRoute(env.getRouterBaseHomePath())); - var href = "".concat(rootPath, "?").concat(REDIRECT_URI, "=").concat(redirectUri); + var appliedRedirectUri = (0, _typeUtil.exists)(redirectUriPath) ? redirectUriPath : env.route.getFullRoute(env.getRouterBaseHomePath()); + var href = "".concat(rootPath, "?").concat(REDIRECT_URI, "=").concat(appliedRedirectUri); window.location.href = href; }, - loginSilently: function loginSilently(dispatch, isSsoCheck) { + loginSilently: function loginSilently(dispatch, isSsoCheck, path, redirectUriPath) { // Until custom domains are implemented, // Safari does not support silent auth flow var allowSilent = AuthService.allowSilentAuth(); @@ -184,7 +184,7 @@ var AuthService = { } if (!allowSilent) { - AuthService.login(); + AuthService.login(path, redirectUriPath); return; } @@ -218,17 +218,17 @@ var AuthService = { logout: function logout(path, redirectUriPath) { var env = _NeonEnvironment.default; var rootPath = (0, _typeUtil.exists)(path) ? path : env.getFullAuthPath('logout'); - var appliedRedirectUri = (0, _typeUtil.exists)(redirectUriPath) ? "".concat(env.getHost()).concat(redirectUriPath) : "".concat(env.getHost()).concat(env.route.getFullRoute(env.getRouterBaseHomePath())); + var appliedRedirectUri = (0, _typeUtil.exists)(redirectUriPath) ? "".concat(env.getApiHost()).concat(redirectUriPath) : "".concat(env.getApiHost()).concat(env.route.getFullRoute(env.getRouterBaseHomePath())); var href = "".concat(rootPath, "?").concat(REDIRECT_URI, "=").concat(appliedRedirectUri); window.location.href = href; }, - logoutSilently: function logoutSilently(dispatch) { + logoutSilently: function logoutSilently(dispatch, path, redirectUriPath) { // Until custom domains are implemented, // Safari does not support silent auth flow var allowSilent = AuthService.allowSilentAuth(); if (!allowSilent) { - AuthService.logout(); + AuthService.logout(path, redirectUriPath); return; } diff --git a/lib/components/NeonAuth/NeonAuth.js b/lib/components/NeonAuth/NeonAuth.js index 2dd90e70..ccf77046 100644 --- a/lib/components/NeonAuth/NeonAuth.js +++ b/lib/components/NeonAuth/NeonAuth.js @@ -25,6 +25,8 @@ var _NeonEnvironment = _interopRequireDefault(require("../NeonEnvironment/NeonEn var _Theme = _interopRequireDefault(require("../Theme/Theme")); +var _typeUtil = require("../../util/typeUtil"); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } @@ -85,7 +87,7 @@ var triggerAuth = function triggerAuth(path, login, dispatch, redirectUriPath) { }); setTimeout(function () { if (login) { - _AuthService.default.login(path); + _AuthService.default.login(path, redirectUriPath); } else { _AuthService.default.logout(path, redirectUriPath); } @@ -107,15 +109,21 @@ var renderAuth = function renderAuth(props, classes, isAuthenticated, showAuthWo appliedLoginType = NeonAuthType.REDIRECT; } + var appHomePath = _NeonEnvironment.default.getRouterBaseHomePath(); + + var currentPath = window.location.pathname; + var hasPath = (0, _typeUtil.isStringNonEmpty)(currentPath) && currentPath.includes(appHomePath); + var redirectUriPath = hasPath ? currentPath : undefined; + switch (appliedLoginType) { case NeonAuthType.SILENT: - _AuthService.default.loginSilently(dispatch, false); + _AuthService.default.loginSilently(dispatch, false, loginPath, redirectUriPath); break; case NeonAuthType.REDIRECT: default: - triggerAuth(loginPath, true, dispatch); + triggerAuth(loginPath, true, dispatch, redirectUriPath); break; } }; @@ -128,16 +136,21 @@ var renderAuth = function renderAuth(props, classes, isAuthenticated, showAuthWo appliedLogoutType = NeonAuthType.REDIRECT; } - var appPath = _NeonEnvironment.default.getRouterBaseHomePath() || ''; + var appHomePath = _NeonEnvironment.default.getRouterBaseHomePath(); - if (_AuthService.LOGOUT_REDIRECT_PATHS.indexOf(appPath) >= 0) { + if (_AuthService.LOGOUT_REDIRECT_PATHS.indexOf(appHomePath) >= 0) { appliedLogoutType = NeonAuthType.REDIRECT; redirectUriPath = _NeonEnvironment.default.route.home(); + } else { + // If not a auto redirect path, redirect back to the current path + var currentPath = window.location.pathname; + var hasPath = (0, _typeUtil.isStringNonEmpty)(currentPath) && currentPath.includes(appHomePath); + redirectUriPath = hasPath ? currentPath : appHomePath; } switch (appliedLogoutType) { case NeonAuthType.SILENT: - _AuthService.default.logoutSilently(dispatch); + _AuthService.default.logoutSilently(dispatch, logoutPath, redirectUriPath); break; diff --git a/lib/components/NeonContext/NeonContext.d.ts b/lib/components/NeonContext/NeonContext.d.ts index 9152d8d0..4e82a05e 100644 --- a/lib/components/NeonContext/NeonContext.d.ts +++ b/lib/components/NeonContext/NeonContext.d.ts @@ -1,8 +1,8 @@ export namespace FETCH_STATUS { - export const AWAITING_CALL: string; - export const FETCHING: string; - export const ERROR: string; - export const SUCCESS: string; + const AWAITING_CALL: string; + const FETCHING: string; + const ERROR: string; + const SUCCESS: string; } export default NeonContext; export function getTestableItems(): { @@ -32,10 +32,10 @@ declare function Provider(props: any): JSX.Element; declare namespace Provider { export { ProviderPropTypes as propTypes }; export namespace defaultProps { - export const children: null; - export const fetchPartials: boolean; - export const useCoreAuth: boolean; - export function whenFinal(): void; + const children: null; + const fetchPartials: boolean; + const useCoreAuth: boolean; + function whenFinal(): void; } } /** @@ -1003,7 +1003,7 @@ declare function useNeonContextState(): ({ whenFinalCalled: boolean; })[]; declare namespace DEFAULT_STATE { - export namespace data { + namespace data { export const sites: {}; export { statesJSON as states }; export { domainsJSON as domains }; @@ -1012,10 +1012,10 @@ declare namespace DEFAULT_STATE { export const stateSites: {}; export const domainSites: {}; } - export const html: { + const html: { [x: number]: null; }; - export const fetches: { + const fetches: { [x: number]: { status: null; error: null; @@ -1029,17 +1029,17 @@ declare namespace DEFAULT_STATE { error: null; }; }; - export namespace auth { - export const useCore: boolean; - export const isAuthenticated: boolean; - export const isAuthWorking: boolean; - export const isAuthWsConnected: boolean; - export const userData: null; + namespace auth { + const useCore: boolean; + const isAuthenticated: boolean; + const isAuthWorking: boolean; + const isAuthWsConnected: boolean; + const userData: null; } - export const isActive: boolean; - export const isFinal: boolean; - export const hasError: boolean; - export const whenFinalCalled: boolean; + const isActive: boolean; + const isFinal: boolean; + const hasError: boolean; + const whenFinalCalled: boolean; } /** getWrappedComponent diff --git a/lib/components/NeonContext/NeonContext.js b/lib/components/NeonContext/NeonContext.js index 1d23b7b9..0539134f 100644 --- a/lib/components/NeonContext/NeonContext.js +++ b/lib/components/NeonContext/NeonContext.js @@ -192,13 +192,13 @@ var reducer = function reducer(state, action) { case 'fetchSitesSucceeded': newState.fetches.sites.status = FETCH_STATUS.SUCCESS; newState.data.sites = action.sites; - newState.isFinal = true; + newState.isFinal = !newState.auth.useCore || newState.fetches.auth.status === FETCH_STATUS.SUCCESS || newState.fetches.auth.status === FETCH_STATUS.ERROR; return deriveRegionSites(newState); case 'fetchSitesFailed': newState.fetches.sites.status = FETCH_STATUS.ERROR; newState.fetches.sites.error = action.error; - newState.isFinal = true; + newState.isFinal = !newState.auth.useCore || newState.fetches.auth.status === FETCH_STATUS.SUCCESS || newState.fetches.auth.status === FETCH_STATUS.ERROR; newState.hasError = true; return newState; // Actions for handling auth fetch @@ -219,6 +219,7 @@ var reducer = function reducer(state, action) { newState.fetches.auth.status = FETCH_STATUS.SUCCESS; newState.auth.isAuthenticated = !!action.isAuthenticated; newState.auth.userData = _AuthService.default.parseUserData(action.response); + newState.isFinal = newState.fetches.sites.status === FETCH_STATUS.SUCCESS || newState.fetches.sites.status === FETCH_STATUS.ERROR; return newState; case 'fetchAuthFailed': @@ -226,6 +227,7 @@ var reducer = function reducer(state, action) { newState.fetches.auth.error = action.error; newState.auth.isAuthenticated = false; newState.auth.userData = null; + newState.isFinal = newState.fetches.sites.status === FETCH_STATUS.SUCCESS || newState.fetches.sites.status === FETCH_STATUS.ERROR; return newState; // Actions for handling remote assets @@ -403,7 +405,11 @@ var Provider = function Provider(props) { _AuthService.default.loginSilently(dispatch, true); } } else { - _AuthService.default.login(); + dispatch({ + type: 'fetchAuthSucceeded', + isAuthenticated: isAuthenticated, + response: response + }); } } else { dispatch({ diff --git a/lib/components/NeonEnvironment/NeonEnvironment.d.ts b/lib/components/NeonEnvironment/NeonEnvironment.d.ts index 3ca244f3..e71d6ecd 100644 --- a/lib/components/NeonEnvironment/NeonEnvironment.d.ts +++ b/lib/components/NeonEnvironment/NeonEnvironment.d.ts @@ -1,78 +1,71 @@ -export const requiredEnvironmentVars: string[]; -export const optionalEnvironmentVars: string[]; -export default NeonEnvironment; -declare namespace NeonEnvironment { - export const isValid: boolean; - export const isDevEnv: boolean; - export const isProdEnv: boolean; - export const isForeignEnv: boolean; - export const useGraphql: boolean; - export const showAopViewer: boolean; - export const authDisableWs: boolean; - export function getApiName(): string | undefined; - export function getApiVersion(): string | undefined; - export function getRootApiPath(): string; - export function getRootGraphqlPath(): string | undefined; - export function getRootJsonLdPath(): string; - export function getRootAuthApiPath(): string | undefined; - export namespace getApiPath { - export function aopDownload(): string | undefined; - export function data(): string | undefined; - export function documents(): string | undefined; - export function download(): string | undefined; - export function manifest(): string | undefined; - export function menu(): string | undefined; - export function products(): string | undefined; - export function releases(): string | undefined; - export function sites(): string | undefined; - export function locations(): string | undefined; - export function arcgisAssets(): string; - } - export namespace getApiLdPath { - export function repo(): string | undefined; - } - export namespace getPagePath { - export function fileNamingConventions(): string | undefined; - } - export namespace getAuthPath { - export function login(): string | undefined; - export function logout(): string | undefined; - export function userInfo(): string | undefined; - export function seamlessLogin(): string; - export function silentLogin(): string; - export function silentLogout(): string; - } - export namespace getAuthApiPath { - export function ws(): string | undefined; - } - export namespace authTopics { - export function getAuth0(): string | undefined; - } - export function getVisusProductsBaseUrl(): string | undefined; - export function getVisusIframeBaseUrl(): string | undefined; - export function getRouterBasePath(): string | undefined; - export function getRouterBaseHomePath(): string | undefined; - export function getHostOverride(): string | undefined; - export function getWsHostOverride(): string | undefined; - export namespace route { - export function home(): string; - export function account(): string; - export function getFullRoute(route?: string): string; - export function buildRouteFromHost(route?: string): string; - export function buildHomeRoute(): string; - export function buildAccountRoute(): string; - } - export function getNeonServerData(): Object; - export function getHost(): string | undefined; - export function getWebSocketHost(): string | undefined; - export function getApiTokenHeader(): string; - export function getApiToken(): string; - export function getAuthSilentType(): AuthSilentType; - export function getFullApiPath(path?: string): string; - export function getFullJsonLdApiPath(path?: string): string; - export function getFullPagePath(path?: string): string; - export function getFullAuthPath(path?: string): string; - export function getFullAuthApiPath(path?: string, useWs?: boolean): string; - export function getFullGraphqlPath(): string; +import { AuthSilentType, Undef } from '../../types/core'; +export declare const DEFAULT_API_HOST = "https://data.neonscience.org"; +export declare const DEFAULT_WEB_HOST = "https://www.neonscience.org"; +interface IHostRegexService { + getApiHostRegex: () => RegExp; + getWebHostRegex: () => RegExp; + getDataCiteApiHostRegex: () => RegExp; +} +export declare const HostRegexService: IHostRegexService; +export declare const requiredEnvironmentVars: string[]; +export declare const optionalEnvironmentVars: string[]; +export interface NeonServerData { + NeonPublicAPIHost: Undef; + NeonWebHost: Undef; + NeonPublicAPITokenHeader: Undef; + NeonPublicAPIToken: Undef; + NeonAuthSilentType: Undef; + DataCiteAPIHost: Undef; } -import { AuthSilentType } from "../../types/core"; +export interface INeonEnvironment { + isValid: boolean; + isDevEnv: boolean; + isProdEnv: boolean; + useGraphql: boolean; + showAopViewer: boolean; + authDisableWs: boolean; + getRootApiPath: () => string; + getRootGraphqlPath: () => string; + getRootJsonLdPath: () => string; + getRootAuthApiPath: () => string; + getRootAuth0ApiPath: () => string; + getRootDownloadApiPath: () => string; + getApiPath: Record string>; + getApiLdPath: Record string>; + getAuthApiPath: Record string>; + getDownloadApiPath: Record string>; + getAuthPath: Record string>; + authTopics: Record string>; + getVisusProductsBaseUrl: () => Undef; + getVisusIframeBaseUrl: () => Undef; + getDataCiteApiHostDefault: () => string; + getRouterBasePath: () => string; + getRouterBaseHomePath: () => string; + getApiHostOverride: () => string; + getWebHostOverride: () => string; + getWsHostOverride: () => string; + getDataCiteApiHostOverride: () => Undef; + route: Record string>; + getNeonServerData: () => NeonServerData | null; + getNeonServerDataWebHost: () => string | null; + getNeonServerDataApiHost: () => string | null; + getNeonServerDataDataCiteApiHost: () => string | null; + getWebHost: () => string; + getApiHost: () => string; + getWebSocketHost: () => string; + getDataCiteApiHost: () => string; + isApiHostValid: (host: string) => boolean; + isWebHostValid: (host: string) => boolean; + isDataCiteApiHostValid: (host: string) => boolean; + getApiTokenHeader: () => string; + getApiToken: () => string; + getAuthSilentType: () => AuthSilentType; + getFullApiPath: (path: string) => string; + getFullJsonLdApiPath: (path: string) => string; + getFullAuthApiPath: (path: string, useWs: boolean) => string; + getFullGraphqlPath: () => string; + getFullDownloadApiPath: (path: string) => string; + getFullAuthPath: (path: string) => string; +} +declare const NeonEnvironment: INeonEnvironment; +export default NeonEnvironment; diff --git a/lib/components/NeonEnvironment/NeonEnvironment.js b/lib/components/NeonEnvironment/NeonEnvironment.js index 9e5b3684..6be8b58b 100644 --- a/lib/components/NeonEnvironment/NeonEnvironment.js +++ b/lib/components/NeonEnvironment/NeonEnvironment.js @@ -3,26 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = exports.optionalEnvironmentVars = exports.requiredEnvironmentVars = void 0; +exports.default = exports.optionalEnvironmentVars = exports.requiredEnvironmentVars = exports.HostRegexService = exports.DEFAULT_WEB_HOST = exports.DEFAULT_API_HOST = void 0; var _core = require("../../types/core"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -// Names of all environment variables that MUST be explicitly defined for the +// Default hosts +var DEFAULT_API_HOST = 'https://data.neonscience.org'; +exports.DEFAULT_API_HOST = DEFAULT_API_HOST; +var DEFAULT_WEB_HOST = 'https://www.neonscience.org'; +exports.DEFAULT_WEB_HOST = DEFAULT_WEB_HOST; +var HostRegexService = { + getApiHostRegex: function getApiHostRegex() { + return new RegExp(/^(data|cert-data|int-data|local-data)[.]neonscience[.]org$/); + }, + getWebHostRegex: function getWebHostRegex() { + return new RegExp(/^(www|cert-www|int-www|local-www)[.](neonscience[.]org|.+[.]us-[0-9]{1}[.]platformsh[.]site)$/); + }, + getDataCiteApiHostRegex: function getDataCiteApiHostRegex() { + return new RegExp(/^(api|api[.]test)[.]datacite[.]org$/); + } +}; // Names of all environment variables that MUST be explicitly defined for the // environment to be reported as "valid". These are evnironment variables // that are expected to be referenced by all apps. Standard vars present in all // node environments (e.g. PORT, NODE_ENV, etc.) are not listed here. -var requiredEnvironmentVars = ['REACT_APP_NEON_API_NAME', 'REACT_APP_NEON_API_VERSION', 'REACT_APP_NEON_AUTH_API', 'REACT_APP_NEON_AUTH_WS_API', 'REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API', 'REACT_APP_NEON_AUTH_LOGIN', 'REACT_APP_NEON_AUTH_LOGOUT', 'REACT_APP_NEON_AUTH_USERINFO', 'REACT_APP_NEON_PATH_MENU_API', 'REACT_APP_NEON_PATH_PUBLIC_GRAPHQL', 'REACT_APP_NEON_ROUTER_BASE', 'REACT_APP_NEON_ROUTER_BASE_HOME', 'REACT_APP_NEON_USE_GRAPHQL']; // Names of additional environment variables that may be referenced by + +exports.HostRegexService = HostRegexService; +var requiredEnvironmentVars = ['REACT_APP_NEON_PATH_API', 'REACT_APP_NEON_PATH_PUBLIC_GRAPHQL', 'REACT_APP_NEON_PATH_AUTH_API', 'REACT_APP_NEON_PATH_AUTH0_API', 'REACT_APP_NEON_ROUTER_BASE', 'REACT_APP_NEON_ROUTER_BASE_HOME']; // Names of additional environment variables that may be referenced by // this module depending on a given app's use case. Along with the above // required list this makes a complete set of all environment variables // this module will ever reference. exports.requiredEnvironmentVars = requiredEnvironmentVars; -var optionalEnvironmentVars = ['REACT_APP_NEON_PATH_LD_API', 'REACT_APP_NEON_PATH_LD_REPO_API', 'REACT_APP_NEON_PATH_AOP_DOWNLOAD_API', 'REACT_APP_NEON_PATH_DATA_API', 'REACT_APP_NEON_PATH_DOCUMENTS_API', 'REACT_APP_NEON_PATH_DOWNLOAD_API', 'REACT_APP_NEON_PATH_MANIFEST_API', 'REACT_APP_NEON_PATH_PRODUCTS_API', 'REACT_APP_NEON_PATH_PROTOTYPE_DATA_API', 'REACT_APP_NEON_PATH_RELEASES_API', 'REACT_APP_NEON_PATH_SITES_API', 'REACT_APP_NEON_PATH_LOCATIONS_API', 'REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS', 'REACT_APP_NEON_SHOW_AOP_VIEWER', 'REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL', 'REACT_APP_NEON_VISUS_IFRAME_BASE_URL', 'REACT_APP_NEON_HOST_OVERRIDE', 'REACT_APP_NEON_WS_HOST_OVERRIDE', 'REACT_APP_FOREIGN_LOCATION', 'REACT_APP_NEON_AUTH_DISABLE_WS', 'REACT_APP_NEON_ROUTER_NEON_HOME', 'REACT_APP_NEON_ROUTER_NEON_MYACCOUNT']; // Temporary paths that shouldn't need to propogate to environment files until made more permanent - +var optionalEnvironmentVars = ['REACT_APP_NEON_PATH_LD_API', 'REACT_APP_NEON_PATH_DOWNLOAD_API', 'REACT_APP_NEON_AUTH_DISABLE_WS', 'REACT_APP_NEON_USE_GRAPHQL', 'REACT_APP_NEON_SHOW_AOP_VIEWER', 'REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL', 'REACT_APP_NEON_VISUS_IFRAME_BASE_URL', 'REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST', 'REACT_APP_NEON_API_HOST_OVERRIDE', 'REACT_APP_NEON_WEB_HOST_OVERRIDE', 'REACT_APP_NEON_WS_HOST_OVERRIDE', 'REACT_APP_NEON_DATA_CITE_API_HOST_OVERRIDE']; exports.optionalEnvironmentVars = optionalEnvironmentVars; -var REACT_APP_NEON_PATH_ARCGIS_ASSETS_API = '/arcgis-assets'; var EnvType = { DEV: 'development', PROD: 'production' @@ -33,85 +48,90 @@ var NeonEnvironment = { }), isDevEnv: process.env.NODE_ENV === EnvType.DEV, isProdEnv: process.env.NODE_ENV === EnvType.PROD, - isForeignEnv: process.env.REACT_APP_FOREIGN_LOCATION === 'true', useGraphql: process.env.REACT_APP_NEON_USE_GRAPHQL === 'true', showAopViewer: process.env.REACT_APP_NEON_SHOW_AOP_VIEWER === 'true', authDisableWs: process.env.REACT_APP_NEON_AUTH_DISABLE_WS === 'true', - getApiName: function getApiName() { - return process.env.REACT_APP_NEON_API_NAME; - }, - getApiVersion: function getApiVersion() { - return process.env.REACT_APP_NEON_API_VERSION; - }, getRootApiPath: function getRootApiPath() { - return "/".concat(process.env.REACT_APP_NEON_API_NAME, "/").concat(process.env.REACT_APP_NEON_API_VERSION); + return process.env.REACT_APP_NEON_PATH_API || '/api/v0'; }, getRootGraphqlPath: function getRootGraphqlPath() { - return process.env.REACT_APP_NEON_PATH_PUBLIC_GRAPHQL; + return process.env.REACT_APP_NEON_PATH_PUBLIC_GRAPHQL || '/graphql'; }, getRootJsonLdPath: function getRootJsonLdPath() { return "".concat(NeonEnvironment.getRootApiPath()).concat(process.env.REACT_APP_NEON_PATH_LD_API); }, getRootAuthApiPath: function getRootAuthApiPath() { - return process.env.REACT_APP_NEON_AUTH_API; + return process.env.REACT_APP_NEON_PATH_AUTH_API || '/api/auth/v0'; + }, + getRootAuth0ApiPath: function getRootAuth0ApiPath() { + return process.env.REACT_APP_NEON_PATH_AUTH0_API || '/auth0'; + }, + getRootDownloadApiPath: function getRootDownloadApiPath() { + return process.env.REACT_APP_NEON_PATH_DOWNLOAD_API || '/api/download/v0'; }, getApiPath: { - aopDownload: function aopDownload() { - return process.env.REACT_APP_NEON_PATH_AOP_DOWNLOAD_API; - }, data: function data() { - return process.env.REACT_APP_NEON_PATH_DATA_API; + return '/data'; }, prototype: function prototype() { - return process.env.REACT_APP_NEON_PATH_PROTOTYPE_DATA_API; + return '/prototype'; }, documents: function documents() { - return process.env.REACT_APP_NEON_PATH_DOCUMENTS_API; - }, - download: function download() { - return process.env.REACT_APP_NEON_PATH_DOWNLOAD_API; - }, - manifest: function manifest() { - return process.env.REACT_APP_NEON_PATH_MANIFEST_API; - }, - menu: function menu() { - return process.env.REACT_APP_NEON_PATH_MENU_API; + return '/documents'; }, products: function products() { - return process.env.REACT_APP_NEON_PATH_PRODUCTS_API; + return '/products'; }, releases: function releases() { - return process.env.REACT_APP_NEON_PATH_RELEASES_API; + return '/releases'; }, sites: function sites() { - return process.env.REACT_APP_NEON_PATH_SITES_API; + return '/sites'; }, locations: function locations() { - return process.env.REACT_APP_NEON_PATH_LOCATIONS_API; + return '/locations'; + }, + samples: function samples() { + return '/samples'; + }, + taxonomy: function taxonomy() { + return '/taxonomy'; + }, + taxonomyDownload: function taxonomyDownload() { + return '/taxonomy/download'; }, arcgisAssets: function arcgisAssets() { - return REACT_APP_NEON_PATH_ARCGIS_ASSETS_API; + return '/arcgis-assets'; } }, - getApiLdPath: { - repo: function repo() { - return process.env.REACT_APP_NEON_PATH_LD_REPO_API; + getDownloadApiPath: { + downloadStream: function downloadStream() { + return '/stream'; + }, + manifestRollup: function manifestRollup() { + return '/manifest/rollup'; + }, + prototypeDownloadStream: function prototypeDownloadStream() { + return '/prototype/stream'; + }, + prototypeManifestRollup: function prototypeManifestRollup() { + return '/prototype/manifest/rollup'; } }, - getPagePath: { - fileNamingConventions: function fileNamingConventions() { - return process.env.REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS; + getApiLdPath: { + repo: function repo() { + return '/repository'; } }, getAuthPath: { login: function login() { - return process.env.REACT_APP_NEON_AUTH_LOGIN; + return "".concat(NeonEnvironment.getRootAuth0ApiPath(), "/login"); }, logout: function logout() { - return process.env.REACT_APP_NEON_AUTH_LOGOUT; + return "".concat(NeonEnvironment.getRootAuth0ApiPath(), "/logout"); }, userInfo: function userInfo() { - return process.env.REACT_APP_NEON_AUTH_USERINFO; + return "".concat(NeonEnvironment.getRootAuth0ApiPath(), "/userinfo"); }, seamlessLogin: function seamlessLogin() { return "".concat(NeonEnvironment.getAuthPath.login(), "?seamless=true"); @@ -121,16 +141,19 @@ var NeonEnvironment = { }, silentLogout: function silentLogout() { return "".concat(NeonEnvironment.getAuthPath.logout(), "?silent=true"); + }, + notifications: function notifications() { + return "".concat(NeonEnvironment.getRootAuth0ApiPath(), "/liferaynotifications"); } }, getAuthApiPath: { ws: function ws() { - return process.env.REACT_APP_NEON_AUTH_WS_API; + return '/ws'; } }, authTopics: { getAuth0: function getAuth0() { - return process.env.REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API; + return '/consumer/topic/auth0'; } }, getVisusProductsBaseUrl: function getVisusProductsBaseUrl() { @@ -139,24 +162,33 @@ var NeonEnvironment = { getVisusIframeBaseUrl: function getVisusIframeBaseUrl() { return process.env.REACT_APP_NEON_VISUS_IFRAME_BASE_URL; }, + getDataCiteApiHostDefault: function getDataCiteApiHostDefault() { + return process.env.REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST || ''; + }, getRouterBasePath: function getRouterBasePath() { - return process.env.REACT_APP_NEON_ROUTER_BASE; + return process.env.REACT_APP_NEON_ROUTER_BASE || ''; }, getRouterBaseHomePath: function getRouterBaseHomePath() { - return process.env.REACT_APP_NEON_ROUTER_BASE_HOME; + return process.env.REACT_APP_NEON_ROUTER_BASE_HOME || ''; + }, + getApiHostOverride: function getApiHostOverride() { + return process.env.REACT_APP_NEON_API_HOST_OVERRIDE || DEFAULT_API_HOST; }, - getHostOverride: function getHostOverride() { - return process.env.REACT_APP_NEON_HOST_OVERRIDE; + getWebHostOverride: function getWebHostOverride() { + return process.env.REACT_APP_NEON_WEB_HOST_OVERRIDE || DEFAULT_WEB_HOST; }, getWsHostOverride: function getWsHostOverride() { - return process.env.REACT_APP_NEON_WS_HOST_OVERRIDE; + return process.env.REACT_APP_NEON_WS_HOST_OVERRIDE || DEFAULT_API_HOST; + }, + getDataCiteApiHostOverride: function getDataCiteApiHostOverride() { + return process.env.REACT_APP_NEON_DATA_CITE_API_HOST_OVERRIDE; }, route: { home: function home() { - return process.env.REACT_APP_NEON_ROUTER_NEON_HOME || '/home'; + return '/home'; }, account: function account() { - return process.env.REACT_APP_NEON_ROUTER_NEON_MYACCOUNT || '/myaccount'; + return '/myaccount'; }, getFullRoute: function getFullRoute() { var route = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; @@ -164,13 +196,15 @@ var NeonEnvironment = { }, buildRouteFromHost: function buildRouteFromHost() { var route = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - return "".concat(NeonEnvironment.getHost()).concat(NeonEnvironment.route.getFullRoute(route)); + return "".concat(NeonEnvironment.getApiHost()).concat(NeonEnvironment.route.getFullRoute(route)); }, buildHomeRoute: function buildHomeRoute() { - return "".concat(NeonEnvironment.getHost()).concat(NeonEnvironment.route.home()); + return "".concat(NeonEnvironment.getWebHost()).concat(NeonEnvironment.route.home()); }, buildAccountRoute: function buildAccountRoute() { - return "".concat(NeonEnvironment.getHost()).concat(NeonEnvironment.route.account()); + return (// TODO: replace with web host once switch over happens + "".concat(NeonEnvironment.getApiHost()).concat(NeonEnvironment.route.account()) + ); } }, @@ -180,39 +214,224 @@ var NeonEnvironment = { */ getNeonServerData: function getNeonServerData() { /* eslint-disable */ + // @ts-ignore if (typeof WorkerGlobalScope === 'function') { + // @ts-ignore return self.NEON_SERVER_DATA ? self.NEON_SERVER_DATA : null; } /* eslint-enable */ if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === 'object') { + // @ts-ignore return window.NEON_SERVER_DATA ? window.NEON_SERVER_DATA : null; } return null; }, - getHost: function getHost() { - if ((NeonEnvironment.isDevEnv || NeonEnvironment.isForeignEnv) && NeonEnvironment.getHostOverride()) { - return NeonEnvironment.getHostOverride(); + getNeonServerDataWebHost: function getNeonServerDataWebHost() { + var serverData = NeonEnvironment.getNeonServerData(); + + if (serverData && typeof serverData.NeonWebHost === 'string') { + var apiHost = serverData.NeonWebHost; + + try { + var _URL = new URL(apiHost), + apiHostname = _URL.hostname; + + if (NeonEnvironment.isWebHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse web host as URL', [e]); + } + } + + return null; + }, + getNeonServerDataApiHost: function getNeonServerDataApiHost() { + var serverData = NeonEnvironment.getNeonServerData(); + + if (serverData && typeof serverData.NeonPublicAPIHost === 'string') { + var apiHost = serverData.NeonPublicAPIHost; + + try { + var _URL2 = new URL(apiHost), + apiHostname = _URL2.hostname; + + if (NeonEnvironment.isApiHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse API host as URL', [e]); + } + } + + return null; + }, + getNeonServerDataDataCiteApiHost: function getNeonServerDataDataCiteApiHost() { + var serverData = NeonEnvironment.getNeonServerData(); + + if (serverData && typeof serverData.DataCiteAPIHost === 'string') { + var apiHost = serverData.DataCiteAPIHost; + + try { + var _URL3 = new URL(apiHost), + apiHostname = _URL3.hostname; + + if (NeonEnvironment.isDataCiteApiHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse DataCite API host as URL', [e]); + } + } + + return null; + }, + getWebHost: function getWebHost() { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getWebHostOverride()) { + return NeonEnvironment.getWebHostOverride(); + } // Check for server data env var + + + var webHost = NeonEnvironment.getNeonServerDataWebHost(); + + if (webHost !== null) { + return webHost; + } + /* eslint-disable */ + // @ts-ignore + + + if (typeof WorkerGlobalScope === 'function' && _typeof(self.location) === 'object') { + if (NeonEnvironment.isWebHostValid(self.location.host)) { + return "".concat(self.location.protocol, "//").concat(self.location.host); + } + + return DEFAULT_WEB_HOST; + } + /* eslint-enable */ + + + if (NeonEnvironment.isWebHostValid(window.location.host)) { + return "".concat(window.location.protocol, "//").concat(window.location.host); + } + + return DEFAULT_WEB_HOST; + }, + getApiHost: function getApiHost() { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getApiHostOverride()) { + return NeonEnvironment.getApiHostOverride(); + } // Check for server data env var + + + var apiHost = NeonEnvironment.getNeonServerDataApiHost(); + + if (apiHost !== null) { + return apiHost; } /* eslint-disable */ + // @ts-ignore if (typeof WorkerGlobalScope === 'function' && _typeof(self.location) === 'object') { - return "".concat(self.location.protocol, "//").concat(self.location.host); + if (NeonEnvironment.isApiHostValid(self.location.host)) { + return "".concat(self.location.protocol, "//").concat(self.location.host); + } + + return DEFAULT_API_HOST; } /* eslint-enable */ - return "".concat(window.location.protocol, "//").concat(window.location.host); + if (NeonEnvironment.isApiHostValid(window.location.host)) { + return "".concat(window.location.protocol, "//").concat(window.location.host); + } + + return DEFAULT_API_HOST; }, getWebSocketHost: function getWebSocketHost() { - if ((NeonEnvironment.isDevEnv || NeonEnvironment.isForeignEnv) && NeonEnvironment.getWsHostOverride()) { + if (NeonEnvironment.isDevEnv && NeonEnvironment.getWsHostOverride()) { return NeonEnvironment.getWsHostOverride(); } - return window.location.protocol.startsWith('https') ? "wss://".concat(window.location.host) : "ws://".concat(window.location.host); + var apiHost = NeonEnvironment.getApiHost(); + var hostUrl = new URL(apiHost); + var apiProtocol = hostUrl.protocol, + apiHostname = hostUrl.hostname; + return apiProtocol.startsWith('https') ? "wss://".concat(apiHostname) : "ws://".concat(apiHostname); + }, + getDataCiteApiHost: function getDataCiteApiHost() { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getDataCiteApiHostOverride()) { + return NeonEnvironment.getDataCiteApiHostOverride(); + } // Check for server data env var + + + var apiHost = NeonEnvironment.getNeonServerDataDataCiteApiHost(); + + if (apiHost !== null) { + return apiHost; + } + + return NeonEnvironment.getDataCiteApiHostDefault(); + }, + + /** + * Valid host names include localhost and known NEON hosts + * @param host + * @returns + */ + isApiHostValid: function isApiHostValid(host) { + if (typeof host !== 'string' || host.length <= 0) { + return false; + } + + var regex = HostRegexService.getApiHostRegex(); + if (!regex) return false; + var matches = regex.exec(host); + if (!matches) return false; + return matches.length > 0; + }, + + /** + * Valid host names include localhost and known NEON hosts + * @param host + * @returns + */ + isWebHostValid: function isWebHostValid(host) { + if (typeof host !== 'string' || host.length <= 0) { + return false; + } + + var regex = HostRegexService.getWebHostRegex(); + if (!regex) return false; + var matches = regex.exec(host); + if (!matches) return false; + return matches.length > 0; + }, + + /** + * Validate the data cite API host + * @param host + * @returns + */ + isDataCiteApiHostValid: function isDataCiteApiHostValid(host) { + if (typeof host !== 'string' || host.length <= 0) { + return false; + } + + var regex = HostRegexService.getDataCiteApiHostRegex(); + if (!regex) return false; + var matches = regex.exec(host); + if (!matches) return false; + return matches.length > 0; }, /** @@ -259,14 +478,19 @@ var NeonEnvironment = { }, getFullApiPath: function getFullApiPath() { var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - var host = NeonEnvironment.getHost(); // Root path (e.g. '/api/v0') doesn't apply to legacy download/manifest-related paths. - - var root = ['aopDownload', 'download', 'manifest'].includes(path) ? '' : NeonEnvironment.getRootApiPath(); + var host = NeonEnvironment.getApiHost(); + var root = ['download', 'manifest'].includes(path) ? '' : NeonEnvironment.getRootApiPath(); return NeonEnvironment.getApiPath[path] ? "".concat(host).concat(root).concat(NeonEnvironment.getApiPath[path]()) : "".concat(host).concat(root); }, + getFullDownloadApiPath: function getFullDownloadApiPath() { + var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var host = NeonEnvironment.getApiHost(); + var root = NeonEnvironment.getRootDownloadApiPath(); + return NeonEnvironment.getDownloadApiPath[path] ? "".concat(host).concat(root).concat(NeonEnvironment.getDownloadApiPath[path]()) : "".concat(host).concat(root); + }, getFullJsonLdApiPath: function getFullJsonLdApiPath() { var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - var host = NeonEnvironment.getHost(); + var host = NeonEnvironment.getApiHost(); var root = NeonEnvironment.getRootJsonLdPath(); var appliedPath = ''; @@ -278,11 +502,6 @@ var NeonEnvironment = { return appliedPath ? "".concat(host).concat(root).concat(appliedPath) : "".concat(host).concat(root); }, - getFullPagePath: function getFullPagePath() { - var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - var host = NeonEnvironment.getHost(); - return NeonEnvironment.getPagePath[path] ? "".concat(host).concat(NeonEnvironment.getPagePath[path]()) : "".concat(host); - }, /** * Creates the full auth path from the host and path. @@ -291,7 +510,7 @@ var NeonEnvironment = { */ getFullAuthPath: function getFullAuthPath() { var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - var host = NeonEnvironment.getHost(); + var host = NeonEnvironment.getApiHost(); return NeonEnvironment.getAuthPath[path] ? "".concat(host).concat(NeonEnvironment.getAuthPath[path]()) : "".concat(host); }, @@ -304,13 +523,13 @@ var NeonEnvironment = { getFullAuthApiPath: function getFullAuthApiPath() { var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var useWs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - var host = useWs ? NeonEnvironment.getWebSocketHost() : NeonEnvironment.getHost(); + var host = useWs ? NeonEnvironment.getWebSocketHost() : NeonEnvironment.getApiHost(); var root = NeonEnvironment.getRootAuthApiPath(); var appliedPath = Object.keys(NeonEnvironment.getAuthApiPath).includes(path) ? NeonEnvironment.getAuthApiPath[path]() : ''; return appliedPath ? "".concat(host).concat(root).concat(appliedPath) : "".concat(host).concat(root); }, getFullGraphqlPath: function getFullGraphqlPath() { - var host = NeonEnvironment.getHost(); + var host = NeonEnvironment.getApiHost(); return "".concat(host).concat(NeonEnvironment.getRootGraphqlPath()); } }; diff --git a/lib/components/NeonEnvironment/package.json b/lib/components/NeonEnvironment/package.json index 7209bb46..3b9b4fd6 100644 --- a/lib/components/NeonEnvironment/package.json +++ b/lib/components/NeonEnvironment/package.json @@ -1,6 +1,6 @@ { "private": true, "name": "neon-environment", - "main": "./NeonEnvironment.js", - "module": "./NeonEnvironment.js" + "main": "./NeonEnvironment.ts", + "module": "./NeonEnvironment.ts" } diff --git a/lib/components/NeonFooter/NeonFooter.d.ts b/lib/components/NeonFooter/NeonFooter.d.ts index df27dd18..3519c747 100644 --- a/lib/components/NeonFooter/NeonFooter.d.ts +++ b/lib/components/NeonFooter/NeonFooter.d.ts @@ -1,10 +1,10 @@ export default NeonFooter; declare function NeonFooter(props: any): JSX.Element; declare namespace NeonFooter { - export namespace propTypes { - export const drupalCssLoaded: PropTypes.Requireable; + namespace propTypes { + const drupalCssLoaded: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const drupalCssLoaded_1: boolean; export { drupalCssLoaded_1 as drupalCssLoaded }; } diff --git a/lib/components/NeonGraphQL/NeonGraphQL.d.ts b/lib/components/NeonGraphQL/NeonGraphQL.d.ts index f8134214..cd79ab7b 100644 --- a/lib/components/NeonGraphQL/NeonGraphQL.d.ts +++ b/lib/components/NeonGraphQL/NeonGraphQL.d.ts @@ -1,22 +1,22 @@ export namespace TYPES { - export const DATA_PRODUCTS: string; - export const SITES: string; - export const LOCATIONS: string; + const DATA_PRODUCTS: string; + const SITES: string; + const LOCATIONS: string; } export namespace DIMENSIONALITIES { - export const ONE: string; - export const MANY: string; + const ONE: string; + const MANY: string; } export default NeonGraphQL; declare namespace NeonGraphQL { - export function getDataProductByCode(productCode: any, release: any): import("rxjs").Observable | import("rxjs").Observable; - export function getAllDataProducts(release: any): import("rxjs").Observable | import("rxjs").Observable; - export function getSiteByCode(siteCode: any): import("rxjs").Observable | import("rxjs").Observable; - export function getAllSites(): import("rxjs").Observable | import("rxjs").Observable; - export function getLocationByName(locationName: any): import("rxjs").Observable | import("rxjs").Observable; - export function getManyLocationsByName(locationNames?: any[]): import("rxjs").Observable | import("rxjs").Observable; - export function getGraphqlQuery(query: string): import("rxjs").Observable | import("rxjs").Observable; - export function getGraphqlAjaxRequest(query: string): { + function getDataProductByCode(productCode: any, release: any): import("rxjs").Observable | import("rxjs").Observable; + function getAllDataProducts(release: any): import("rxjs").Observable | import("rxjs").Observable; + function getSiteByCode(siteCode: any): import("rxjs").Observable | import("rxjs").Observable; + function getAllSites(): import("rxjs").Observable | import("rxjs").Observable; + function getLocationByName(locationName: any): import("rxjs").Observable | import("rxjs").Observable; + function getManyLocationsByName(locationNames?: any[]): import("rxjs").Observable | import("rxjs").Observable; + function getGraphqlQuery(query: string): import("rxjs").Observable | import("rxjs").Observable; + function getGraphqlAjaxRequest(query: string): { method: string; crossDomain: boolean; url: string; diff --git a/lib/components/NeonHeader/ApplicationMenu.d.ts b/lib/components/NeonHeader/ApplicationMenu.d.ts index 949c944e..3a5650b3 100644 --- a/lib/components/NeonHeader/ApplicationMenu.d.ts +++ b/lib/components/NeonHeader/ApplicationMenu.d.ts @@ -1,2 +1,7 @@ /// -export default function ApplicationMenu(): JSX.Element | null; +/** + * Return the application menu + * @returns The menu or null if the user has no applications to display. + */ +declare const ApplicationMenu: () => JSX.Element | null; +export default ApplicationMenu; diff --git a/lib/components/NeonHeader/ApplicationMenu.js b/lib/components/NeonHeader/ApplicationMenu.js index f9e0ce54..6afaacfd 100644 --- a/lib/components/NeonHeader/ApplicationMenu.js +++ b/lib/components/NeonHeader/ApplicationMenu.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = ApplicationMenu; +exports.default = void 0; var _react = _interopRequireDefault(require("react")); @@ -156,12 +156,12 @@ var Menu = function Menu(props) { }; // open menu by tab key - function handleMenuKeyDown(event) { + var handleMenuKeyDown = function handleMenuKeyDown(event) { if (event.key === 'Tab') { event.preventDefault(); setOpen(false); } - } // handle a menu selection + }; // handle a menu selection var handleMenuItemClick = function handleMenuItemClick(event, url) { @@ -240,8 +240,13 @@ var Menu = function Menu(props) { }))))); }))); }; +/** + * Return the application menu + * @returns The menu or null if the user has no applications to display. + */ -function ApplicationMenu() { + +var ApplicationMenu = function ApplicationMenu() { var _authData$userData, _authData$userData$da; var _NeonContext$useNeonC = _NeonContext.default.useNeonContextState(), @@ -257,4 +262,7 @@ function ApplicationMenu() { } return null; -} \ No newline at end of file +}; + +var _default = ApplicationMenu; +exports.default = _default; \ No newline at end of file diff --git a/lib/components/NeonHeader/NeonHeader.js b/lib/components/NeonHeader/NeonHeader.js index a9476ba4..7ac6be03 100644 --- a/lib/components/NeonHeader/NeonHeader.js +++ b/lib/components/NeonHeader/NeonHeader.js @@ -272,7 +272,8 @@ var useStyles = (0, _styles.makeStyles)(function (theme) { }); var buildSearchAction = function buildSearchAction(action) { - var root = 'https://www.neonscience.org'; + var root = _NeonEnvironment.default.getWebHost(); + if (!action) return "".concat(root, "/search/site"); if (action.startsWith('/')) { diff --git a/lib/components/NeonJsonLd/NeonJsonLd.d.ts b/lib/components/NeonJsonLd/NeonJsonLd.d.ts index 6e388fbd..0b3870c9 100644 --- a/lib/components/NeonJsonLd/NeonJsonLd.d.ts +++ b/lib/components/NeonJsonLd/NeonJsonLd.d.ts @@ -1,16 +1,16 @@ export default NeonJsonLd; declare namespace NeonJsonLd { - export const CITATION_AUTHOR: string; - export function getJsonLdObservable(url: string): import("rxjs").Observable; - export function getRepoJsonLdObservable(): import("rxjs").Observable; - export function getProductJsonLdObservable(productCode: string, release: string): import("rxjs").Observable; - export function inject(data: Object | null | undefined, injectReleaseMeta?: boolean): void; - export function injectReleaseMeta(data: Object | null | undefined): void; - export function removeAllMetadata(): void; - export function removeJsonLdScript(): void; - export function removeReleaseMeta(): void; - export function getJsonLdWithInjection(url: string, injectReleaseMeta?: boolean): void; - export function injectRepo(): void; - export function injectProduct(productCode: string, release: string, injectReleaseMeta?: boolean, onNotExistsOnly?: boolean): void | null; - export function injectPrototypeDataset(uuid: string, onNotExistsOnly?: boolean): void | null; + const CITATION_AUTHOR: string; + function getJsonLdObservable(url: string): import("rxjs").Observable; + function getRepoJsonLdObservable(): import("rxjs").Observable; + function getProductJsonLdObservable(productCode: string, release: string): import("rxjs").Observable; + function inject(data: Object | null | undefined, injectReleaseMeta?: boolean): void; + function injectReleaseMeta(data: Object | null | undefined): void; + function removeAllMetadata(): void; + function removeJsonLdScript(): void; + function removeReleaseMeta(): void; + function getJsonLdWithInjection(url: string, injectReleaseMeta?: boolean): void; + function injectRepo(): void; + function injectProduct(productCode: string, release: string, injectReleaseMeta?: boolean, onNotExistsOnly?: boolean): void | null; + function injectPrototypeDataset(uuid: string, onNotExistsOnly?: boolean): void | null; } diff --git a/lib/components/NeonPage/LiferayNotifications.d.ts b/lib/components/NeonPage/LiferayNotifications.d.ts index abf0f6f5..4444da2a 100644 --- a/lib/components/NeonPage/LiferayNotifications.d.ts +++ b/lib/components/NeonPage/LiferayNotifications.d.ts @@ -1,15 +1,15 @@ export default LiferayNotifications; declare function LiferayNotifications(props: any): JSX.Element | null; declare namespace LiferayNotifications { - export namespace propTypes { - export const notifications: PropTypes.Requireable<(PropTypes.InferProps<{ + namespace propTypes { + const notifications: PropTypes.Requireable<(PropTypes.InferProps<{ id: PropTypes.Validator; message: PropTypes.Validator; dismissed: PropTypes.Validator; }> | null | undefined)[]>; - export const onHideNotifications: PropTypes.Requireable<(...args: any[]) => any>; + const onHideNotifications: PropTypes.Requireable<(...args: any[]) => any>; } - export namespace defaultProps { + namespace defaultProps { const notifications_1: never[]; export { notifications_1 as notifications }; const onHideNotifications_1: null; diff --git a/lib/components/NeonPage/NeonPage.d.ts b/lib/components/NeonPage/NeonPage.d.ts index 3f33b894..c8db7b1b 100644 --- a/lib/components/NeonPage/NeonPage.d.ts +++ b/lib/components/NeonPage/NeonPage.d.ts @@ -1,11 +1,11 @@ export function NeonErrorPage(props: any): JSX.Element; export namespace NeonErrorPage { - export namespace propTypes { - export const error: PropTypes.Validator; stack: PropTypes.Requireable; }>>; - export const resetErrorBoundary: PropTypes.Validator<(...args: any[]) => any>; + const resetErrorBoundary: PropTypes.Validator<(...args: any[]) => any>; } } export default NeonPage; diff --git a/lib/components/ReleaseFilter/ReleaseFilter.js b/lib/components/ReleaseFilter/ReleaseFilter.js index 42400c88..39e92a93 100644 --- a/lib/components/ReleaseFilter/ReleaseFilter.js +++ b/lib/components/ReleaseFilter/ReleaseFilter.js @@ -41,6 +41,8 @@ var _InfoOutlined = _interopRequireDefault(require("@material-ui/icons/InfoOutli var _Theme = _interopRequireDefault(require("../Theme/Theme")); +var _RouteService = _interopRequireDefault(require("../../service/RouteService")); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } @@ -139,7 +141,6 @@ var useStyles = (0, _styles.makeStyles)(function (theme) { var UNSPECIFIED_NAME = 'Latest and Provisional'; var UNSPECIFIED_DESCRIPTION = 'Data in the latest release in addition to provisional data (not yet in any release)'; var DOI_TITLE = 'Digital Object Identifier (DOI) - A citable permanent link to this this data product release'; -var INFO_URL = 'https://www.neonscience.org/data-samples/data-management/data-revisions-releases'; var formatGenerationDate = function formatGenerationDate(generationDate) { var generationMoment = _moment.default.utc(generationDate); @@ -235,7 +236,7 @@ var ReleaseFilter = function ReleaseFilter(props) { }); var releasesLink = /*#__PURE__*/_react.default.createElement(_Link.default, { - href: INFO_URL, + href: _RouteService.default.getDataRevisionsReleasePath(), target: "_blank" }, "Data Product Revisions and Releases"); /* eslint-disable react/jsx-one-expression-per-line */ diff --git a/lib/components/SiteMap/SiteMapContainer.d.ts b/lib/components/SiteMap/SiteMapContainer.d.ts index 47dce529..ad77c5c0 100644 --- a/lib/components/SiteMap/SiteMapContainer.d.ts +++ b/lib/components/SiteMap/SiteMapContainer.d.ts @@ -1,10 +1,10 @@ export default SiteMapContainer; declare function SiteMapContainer(props: any): JSX.Element; declare namespace SiteMapContainer { - export namespace propTypes { - export const unusableVerticalSpace: PropTypes.Requireable; + namespace propTypes { + const unusableVerticalSpace: PropTypes.Requireable; } - export namespace defaultProps { + namespace defaultProps { const unusableVerticalSpace_1: number; export { unusableVerticalSpace_1 as unusableVerticalSpace }; } diff --git a/lib/components/SiteMap/SiteMapContext.d.ts b/lib/components/SiteMap/SiteMapContext.d.ts index 52013da5..0ca3e285 100644 --- a/lib/components/SiteMap/SiteMapContext.d.ts +++ b/lib/components/SiteMap/SiteMapContext.d.ts @@ -53,12 +53,12 @@ declare namespace Provider { tableFullHeight: PropTypes.Requireable; location: PropTypes.Requireable; selection: PropTypes.Requireable; - selectedItems: PropTypes.Requireable[]>; - validItems: PropTypes.Requireable[]>; + selectedItems: PropTypes.Requireable<(string | null | undefined)[]>; + validItems: PropTypes.Requireable<(string | null | undefined)[]>; selectionLimit: (props: any, propName: any) => Error | null; onSelectionChange: PropTypes.Requireable<(...args: any[]) => any>; search: PropTypes.Requireable; - features: PropTypes.Requireable[]>; + features: PropTypes.Requireable<(string | null | undefined)[]>; manualLocationData: PropTypes.Requireable<(PropTypes.InferProps<{ manualLocationType: PropTypes.Validator; }> | null | undefined)[]>; diff --git a/lib/components/SiteMap/SiteMapContext.js b/lib/components/SiteMap/SiteMapContext.js index 8334b2ab..1996f329 100644 --- a/lib/components/SiteMap/SiteMapContext.js +++ b/lib/components/SiteMap/SiteMapContext.js @@ -441,6 +441,28 @@ var updateMapTileWithZoom = function updateMapTileWithZoom(state) { } return newState; +}; +/** + * Calculates the zoom state from the specified zoom + * @param {number} zoom + * @param {Object} newState + * @param {boolean} init + * @return The updated map state + */ + + +var calculateZoomState = function calculateZoomState(zoom, newState) { + var init = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var appliedState = newState; + appliedState.map.zoomedIcons = (0, _SiteMapUtils.getZoomedIcons)(zoom); + appliedState = updateMapTileWithZoom(appliedState); + + if (!init) { + appliedState = (0, _SiteMapUtils.calculateFeatureAvailability)(appliedState); + appliedState = calculateFeatureDataFetches(appliedState); + } + + return appliedState; }; // Increment the completed count for overall fetch and, if completed and expected are now equal, // reset both (so that subsequent batches of fetches can give an accurate progress metric). @@ -794,10 +816,7 @@ var reducer = function reducer(state, action) { newState.map.bounds = action.bounds; } - newState.map.zoomedIcons = (0, _SiteMapUtils.getZoomedIcons)(newState.map.zoom); - newState = updateMapTileWithZoom(newState); - newState = (0, _SiteMapUtils.calculateFeatureAvailability)(newState); - newState = calculateFeatureDataFetches(newState); + newState = calculateZoomState(action.zoom, newState); return newState; case 'setMapBounds': @@ -1270,6 +1289,12 @@ var Provider = function Provider(props) { initialState = (0, _SiteMapUtils.hydrateNeonContextData)(initialState, neonContextData); } + var hasInitialZoom = typeof mapZoom === 'number' && zoomIsValid(mapZoom); + + if (hasInitialZoom) { + initialState = calculateZoomState(initialMapZoom, initialState, true); + } + var _useReducer = (0, _react.useReducer)(reducer, initialState), _useReducer2 = _slicedToArray(_useReducer, 2), state = _useReducer2[0], diff --git a/lib/components/SiteMap/SiteMapFeature.d.ts b/lib/components/SiteMap/SiteMapFeature.d.ts index 14fdbb1b..6257feec 100644 --- a/lib/components/SiteMap/SiteMapFeature.d.ts +++ b/lib/components/SiteMap/SiteMapFeature.d.ts @@ -1,11 +1,11 @@ export default SiteMapFeature; declare function SiteMapFeature(props: any): JSX.Element | null; declare namespace SiteMapFeature { - export namespace propTypes { - export const mapRef: PropTypes.Validator; }>>; - export const featureKey: PropTypes.Validator; + const featureKey: PropTypes.Validator; } } import PropTypes from "prop-types"; diff --git a/lib/components/SiteMap/SiteMapLeaflet.js b/lib/components/SiteMap/SiteMapLeaflet.js index 089d5606..6a6c18e8 100644 --- a/lib/components/SiteMap/SiteMapLeaflet.js +++ b/lib/components/SiteMap/SiteMapLeaflet.js @@ -297,6 +297,11 @@ var SiteMapLeaflet = function SiteMapLeaflet() { if (state.focusLocation.current && state.focusLocation.fetch.status !== _SiteMapUtils.FETCH_STATUS.SUCCESS) { canRender = false; } + + var _useState = (0, _react.useState)(false), + _useState2 = _slicedToArray(_useState, 2), + mapRefReady = _useState2[0], + setMapRefReady = _useState2[1]; /** Effect If zoom was not set as a prop then attempt to set the initial zoom such that @@ -319,22 +324,37 @@ var SiteMapLeaflet = function SiteMapLeaflet() { Effect If map bounds are null (as they will be when setting a focus location) then fill them in We have to do it this way as only the Leaflet Map instance can give us bounds + Effect for setting the initial zoom so that we can include the bounds + of the map in the initial zoom setting to allow proper feature detection. */ + var mapRefExistsProp = mapRefExists(); (0, _react.useEffect)(function () { - if (state.map.bounds !== null || !mapRefExists()) { + if (state.map.bounds !== null || !mapRefExistsProp) { return; } var bounds = mapRef.current.leafletElement.getBounds(); - dispatch({ - type: 'setMapBounds', - bounds: { - lat: [bounds._southWest.lat, bounds._northEast.lat], - lng: [bounds._southWest.lng, bounds._northEast.lng] - } - }); - }, [state.map.bounds, dispatch]); + + if (state.map.zoom === null) { + dispatch({ + type: 'setMapBounds', + bounds: { + lat: [bounds._southWest.lat, bounds._northEast.lat], + lng: [bounds._southWest.lng, bounds._northEast.lng] + } + }); + } else { + dispatch({ + type: 'setMapZoom', + zoom: state.map.zoom, + bounds: { + lat: [bounds._southWest.lat, bounds._northEast.lat], + lng: [bounds._southWest.lng, bounds._northEast.lng] + } + }); + } + }, [mapRefExistsProp, state.map.bounds, state.map.zoom, dispatch]); /** Effect Visually distinguish unselectable markers in the marker pane while also changing the draw order @@ -508,11 +528,6 @@ var SiteMapLeaflet = function SiteMapLeaflet() { */ - var _useState = (0, _react.useState)(false), - _useState2 = _slicedToArray(_useState, 2), - mapRefReady = _useState2[0], - setMapRefReady = _useState2[1]; - (0, _react.useEffect)(function () { // eslint-disable-line react-hooks/exhaustive-deps if (mapRefExists() && !mapRefReady) { diff --git a/lib/components/SiteMap/SiteMapTable.js b/lib/components/SiteMap/SiteMapTable.js index 11c28239..50f88de6 100644 --- a/lib/components/SiteMap/SiteMapTable.js +++ b/lib/components/SiteMap/SiteMapTable.js @@ -785,7 +785,7 @@ var SiteMapTable = function SiteMapTable() { return jumpTo(domain.domainCode); }, title: "Click to view ".concat(domain.domainCode, " on the map") - }, domain.domainCode)); + }, domain.domainCode || '')); } }, state: { @@ -824,7 +824,7 @@ var SiteMapTable = function SiteMapTable() { return jumpTo(stateCode); }, title: "Click to view ".concat(stateCode, " on the map") - }, usstate.name)); + }, usstate.name || '')); } }, coordinates: { @@ -926,7 +926,7 @@ var SiteMapTable = function SiteMapTable() { return jumpTo(name); }, title: "View ".concat(name, " on map") - }, name); + }, name || ''); } }, { // Location Type diff --git a/lib/components/SiteMap/SiteMapUtils.d.ts b/lib/components/SiteMap/SiteMapUtils.d.ts index 7b7aa3e3..25c050a1 100644 --- a/lib/components/SiteMap/SiteMapUtils.d.ts +++ b/lib/components/SiteMap/SiteMapUtils.d.ts @@ -6,43 +6,43 @@ export const KM2_TO_ACRES: 247.10538146717; export const LOCATION_BOUNDS_SAMPLING_MAX: 10000; export const SITE_LOCATION_HIERARCHIES_MIN_ZOOM: 9; export namespace SORT_DIRECTIONS { - export const ASC: string; - export const DESC: string; + const ASC: string; + const DESC: string; } export namespace SITE_TERRAINS { - export const AQUATIC: string; - export const TERRESTRIAL: string; + const AQUATIC: string; + const TERRESTRIAL: string; } export namespace MANUAL_LOCATION_TYPES { - export const PROTOTYPE_SITE: string; + const PROTOTYPE_SITE: string; } export namespace FEATURE_TYPES { - export namespace SITES { - export const unit: string; - export const units: string; - export const selectable: boolean; - export const viewableInTable: boolean; - export const deriveRegionSelections: boolean; - } - export namespace SITE_LOCATION_HIERARCHIES { + namespace SITES { + const unit: string; + const units: string; + const selectable: boolean; + const viewableInTable: boolean; + const deriveRegionSelections: boolean; + } + namespace SITE_LOCATION_HIERARCHIES { const selectable_1: boolean; export { selectable_1 as selectable }; } - export namespace LOCATIONS { + namespace LOCATIONS { const selectable_2: boolean; export { selectable_2 as selectable }; const viewableInTable_1: boolean; export { viewableInTable_1 as viewableInTable }; } - export namespace SAMPLING_POINTS { + namespace SAMPLING_POINTS { const selectable_3: boolean; export { selectable_3 as selectable }; } - export namespace BOUNDARIES { + namespace BOUNDARIES { const selectable_4: boolean; export { selectable_4 as selectable }; } - export namespace DOMAINS { + namespace DOMAINS { const unit_1: string; export { unit_1 as unit }; const units_1: string; @@ -52,7 +52,7 @@ export namespace FEATURE_TYPES { const viewableInTable_2: boolean; export { viewableInTable_2 as viewableInTable }; } - export namespace STATES { + namespace STATES { const unit_2: string; export { unit_2 as unit }; const units_2: string; @@ -62,80 +62,80 @@ export namespace FEATURE_TYPES { const viewableInTable_3: boolean; export { viewableInTable_3 as viewableInTable }; } - export namespace GROUP { + namespace GROUP { const selectable_7: boolean; export { selectable_7 as selectable }; } - export namespace OTHER { + namespace OTHER { const selectable_8: boolean; export { selectable_8 as selectable }; } } export namespace FEATURE_DATA_SOURCES { - export const REST_LOCATIONS_API: string; - export const GRAPHQL_LOCATIONS_API: string; - export const ARCGIS_ASSETS_API: string; - export const NEON_CONTEXT: string; - export const MANUAL_LOCATIONS: string; + const REST_LOCATIONS_API: string; + const GRAPHQL_LOCATIONS_API: string; + const ARCGIS_ASSETS_API: string; + const NEON_CONTEXT: string; + const MANUAL_LOCATIONS: string; } export namespace SELECTION_PORTIONS { - export const PARTIAL: string; - export const TOTAL: string; + const PARTIAL: string; + const TOTAL: string; } export namespace SELECTION_STATUS { - export const SELECTED: string; - export const UNSELECTED: string; + const SELECTED: string; + const UNSELECTED: string; } export const UNSELECTABLE_MARKER_FILTER: "sepia(0.8) contrast(0.3) brightness(1.35)"; export namespace HIGHLIGHT_STATUS { - export const NONE: string; - export const HIGHLIGHT: string; - export const SELECT: string; + const NONE: string; + const HIGHLIGHT: string; + const SELECT: string; } export namespace VIEWS { - export const MAP: string; - export const TABLE: string; - export const SPLIT: string; + const MAP: string; + const TABLE: string; + const SPLIT: string; } export namespace MAP_MOUSE_MODES { - export const PAN: string; - export const AREA_SELECT: string; + const PAN: string; + const AREA_SELECT: string; } export namespace FETCH_STATUS { - export const AWAITING_CALL: string; - export const FETCHING: string; - export const ERROR: string; - export const SUCCESS: string; + const AWAITING_CALL: string; + const FETCHING: string; + const ERROR: string; + const SUCCESS: string; } export namespace PLOT_SAMPLING_MODULES { - export const bbc: string; - export const bet: string; - export const bgc: string; - export const brd: string; - export const cdw: string; - export const cfc: string; - export const dhp: string; - export const div: string; - export const hbp: string; - export const ltr: string; - export const mam: string; - export const mfb: string; - export const mos: string; - export const mpt: string; - export const phe: string; - export const sme: string; - export const tck: string; - export const vst: string; + const bbc: string; + const bet: string; + const bgc: string; + const brd: string; + const cdw: string; + const cfc: string; + const dhp: string; + const div: string; + const hbp: string; + const ltr: string; + const mam: string; + const mfb: string; + const mos: string; + const mpt: string; + const phe: string; + const sme: string; + const tck: string; + const vst: string; } export namespace NLCD_CLASSES { - export namespace openWater { - export const name: string; - export const value: number; - export const description: string; - export const color: string; - export const category: string; - } - export namespace perennialIceSnow { + namespace openWater { + const name: string; + const value: number; + const description: string; + const color: string; + const category: string; + } + namespace perennialIceSnow { const name_1: string; export { name_1 as name }; export const vaule: number; @@ -146,7 +146,7 @@ export namespace NLCD_CLASSES { const category_1: string; export { category_1 as category }; } - export namespace developedOpenSpace { + namespace developedOpenSpace { const name_2: string; export { name_2 as name }; const value_1: number; @@ -158,7 +158,7 @@ export namespace NLCD_CLASSES { const category_2: string; export { category_2 as category }; } - export namespace developedLowIntensity { + namespace developedLowIntensity { const name_3: string; export { name_3 as name }; const value_2: number; @@ -170,7 +170,7 @@ export namespace NLCD_CLASSES { const category_3: string; export { category_3 as category }; } - export namespace developedMediumIntensity { + namespace developedMediumIntensity { const name_4: string; export { name_4 as name }; const value_3: number; @@ -182,7 +182,7 @@ export namespace NLCD_CLASSES { const category_4: string; export { category_4 as category }; } - export namespace developedHighIntensity { + namespace developedHighIntensity { const name_5: string; export { name_5 as name }; const value_4: number; @@ -194,7 +194,7 @@ export namespace NLCD_CLASSES { const category_5: string; export { category_5 as category }; } - export namespace barrenLand { + namespace barrenLand { const name_6: string; export { name_6 as name }; const value_5: number; @@ -206,7 +206,7 @@ export namespace NLCD_CLASSES { const category_6: string; export { category_6 as category }; } - export namespace deciduousForest { + namespace deciduousForest { const name_7: string; export { name_7 as name }; const value_6: number; @@ -218,7 +218,7 @@ export namespace NLCD_CLASSES { const category_7: string; export { category_7 as category }; } - export namespace evergreenForest { + namespace evergreenForest { const name_8: string; export { name_8 as name }; const value_7: number; @@ -230,7 +230,7 @@ export namespace NLCD_CLASSES { const category_8: string; export { category_8 as category }; } - export namespace mixedForest { + namespace mixedForest { const name_9: string; export { name_9 as name }; const value_8: number; @@ -242,7 +242,7 @@ export namespace NLCD_CLASSES { const category_9: string; export { category_9 as category }; } - export namespace dwarfScrub { + namespace dwarfScrub { const name_10: string; export { name_10 as name }; const value_9: number; @@ -254,7 +254,7 @@ export namespace NLCD_CLASSES { const category_10: string; export { category_10 as category }; } - export namespace shrubScrub { + namespace shrubScrub { const name_11: string; export { name_11 as name }; const value_10: number; @@ -266,7 +266,7 @@ export namespace NLCD_CLASSES { const category_11: string; export { category_11 as category }; } - export namespace grasslandHerbaceous { + namespace grasslandHerbaceous { const name_12: string; export { name_12 as name }; const value_11: number; @@ -278,7 +278,7 @@ export namespace NLCD_CLASSES { const category_12: string; export { category_12 as category }; } - export namespace sedgeHerbaceous { + namespace sedgeHerbaceous { const name_13: string; export { name_13 as name }; const value_12: number; @@ -290,7 +290,7 @@ export namespace NLCD_CLASSES { const category_13: string; export { category_13 as category }; } - export namespace lichens { + namespace lichens { const name_14: string; export { name_14 as name }; const value_13: number; @@ -302,7 +302,7 @@ export namespace NLCD_CLASSES { const category_14: string; export { category_14 as category }; } - export namespace moss { + namespace moss { const name_15: string; export { name_15 as name }; const value_14: number; @@ -314,7 +314,7 @@ export namespace NLCD_CLASSES { const category_15: string; export { category_15 as category }; } - export namespace pastureHay { + namespace pastureHay { const name_16: string; export { name_16 as name }; const value_15: number; @@ -326,7 +326,7 @@ export namespace NLCD_CLASSES { const category_16: string; export { category_16 as category }; } - export namespace cultivatedCrops { + namespace cultivatedCrops { const name_17: string; export { name_17 as name }; const value_16: number; @@ -338,7 +338,7 @@ export namespace NLCD_CLASSES { const category_17: string; export { category_17 as category }; } - export namespace woodyWetlands { + namespace woodyWetlands { const name_18: string; export { name_18 as name }; const value_17: number; @@ -350,7 +350,7 @@ export namespace NLCD_CLASSES { const category_18: string; export { category_18 as category }; } - export namespace emergentHerbaceousWetlands { + namespace emergentHerbaceousWetlands { const name_19: string; export { name_19 as name }; const value_18: number; @@ -364,12 +364,12 @@ export namespace NLCD_CLASSES { } } export namespace LOCATION_ICON_SVG_SHAPES { - export namespace CIRCLE { - export const KEY: string; - export const iconSize: number[]; - export const iconAnchor: number[]; - export const popupAnchor: number[]; - export const shadow: { + namespace CIRCLE { + const KEY: string; + const iconSize: number[]; + const iconAnchor: number[]; + const popupAnchor: number[]; + const shadow: { [x: string]: { svg: any; size: number[]; @@ -377,7 +377,7 @@ export namespace LOCATION_ICON_SVG_SHAPES { }; }; } - export namespace DIAMOND { + namespace DIAMOND { const KEY_1: string; export { KEY_1 as KEY }; const iconSize_1: number[]; @@ -395,7 +395,7 @@ export namespace LOCATION_ICON_SVG_SHAPES { }; export { shadow_1 as shadow }; } - export namespace HOMEPLATE { + namespace HOMEPLATE { const KEY_2: string; export { KEY_2 as KEY }; const iconSize_2: number[]; @@ -413,7 +413,7 @@ export namespace LOCATION_ICON_SVG_SHAPES { }; export { shadow_2 as shadow }; } - export namespace SQUARE { + namespace SQUARE { const KEY_3: string; export { KEY_3 as KEY }; const iconSize_3: number[]; @@ -433,708 +433,1212 @@ export namespace LOCATION_ICON_SVG_SHAPES { } } export namespace FEATURES { - const STATES_1: { - name: string; - nameSingular: string; - type: any; - hideByDefault: boolean; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - style: { - color: string; - weight: number; - }; - generalLegendGroup: boolean; - }; + export namespace STATES_1 { + const name_20: string; + export { name_20 as name }; + export const nameSingular: string; + export const type: any; + export const hideByDefault: boolean; + import dataSource = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource }; + export const primaryIdOnly: boolean; + export const featureShape: string; + export namespace style { + const color_20: string; + export { color_20 as color }; + export const weight: number; + } + export const generalLegendGroup: boolean; + } export { STATES_1 as STATES }; - const DOMAINS_1: { - name: string; - nameSingular: string; - type: any; - hideByDefault: boolean; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - style: { - color: string; - weight: number; - }; - }; + export namespace DOMAINS_1 { + const name_21: string; + export { name_21 as name }; + const nameSingular_1: string; + export { nameSingular_1 as nameSingular }; + const type_1: any; + export { type_1 as type }; + const hideByDefault_1: boolean; + export { hideByDefault_1 as hideByDefault }; + import dataSource_1 = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource_1 as dataSource }; + const primaryIdOnly_1: boolean; + export { primaryIdOnly_1 as primaryIdOnly }; + const featureShape_1: string; + export { featureShape_1 as featureShape }; + export namespace style_1 { + const color_21: string; + export { color_21 as color }; + const weight_1: number; + export { weight_1 as weight }; + } + export { style_1 as style }; + } export { DOMAINS_1 as DOMAINS }; - export const FLIGHT_BOX_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const AQUATIC_WATERSHEDS: { - name: string; - type: any; - minZoom: number; - }; - export const WATERSHED_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - parent: string; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const DRAINAGE_LINES: { - name: string; - type: any; - minZoom: number; - dataSource: string; - parent: string; - featureShape: string; - style: { - color: string; - }; - }; - export const POUR_POINTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - }; - export const SAMPLING_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - description: string; - parent: string; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const AQUATIC_REACHES: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - parent: string; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const TOWER_AIRSHEDS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - parent: string; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const TERRESTRIAL_SITE_FEATURES: { - name: string; - type: any; - minZoom: number; - fetchingForFeatures: string[]; - }; - export const TOWERS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const HUTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const MEGAPITS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const TOWER_PLOTS: { - name: string; - type: any; - minZoom: number; - description: string; - parent: string; - }; - export const TOWER_PHENOLOGY_PLOTS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - featureShape: string; - minZoom: number; - focusZoom: number; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const TOWER_BASE_PLOTS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - featureShape: string; - minZoom: number; - focusZoom: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const TOWER_SOIL_PLOTS: { - name: string; - nameSingular: string; - type: any; - dataSource: string; - matchLocationType: string; - description: string; - parent: string; - featureShape: string; - minZoom: number; - focusZoom: number; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const DISTRIBUTED_PLOTS: { - name: string; - type: any; - minZoom: number; - description: string; - parent: string; - }; - export const DISTRIBUTED_BIRD_GRIDS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - featureShape: string; - iconScale: number; - focusZoom: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const DISTRIBUTED_MAMMAL_GRIDS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - featureShape: string; - iconScale: number; - focusZoom: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const DISTRIBUTED_BASE_PLOTS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - featureShape: string; - dataSource: string; - matchLocationType: string; - iconScale: number; - focusZoom: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const DISTRIBUTED_TICK_PLOTS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - featureShape: string; - iconScale: number; - focusZoom: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const DISTRIBUTED_MOSQUITO_POINTS: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - dataSource: string; - matchLocationType: string; - iconSvg: any; - iconShape: string; - featureShape: string; - focusZoom: number; - siteTerrain: string; - }; - export const PLOT_BOUNDARIES: { - name: string; - type: any; - minZoom: number; - description: string; - parent: string; - }; - export const TOWER_PHENOLOGY_PLOT_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - descriptionFromParentDataFeatureKey: boolean; - parent: string; - parentDataFeatureKey: string; - dataSource: string; - matchLocationName: RegExp; - matchLocationCoordinateMap: string[]; - minZoom: number; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - siteTerrain: string; - }; - export const TOWER_SOIL_PLOT_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - descriptionFromParentDataFeatureKey: boolean; - parent: string; - parentDataFeatureKey: string; - minZoom: number; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - }; - export const DISTRIBUTED_BIRD_GRID_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - descriptionFromParentDataFeatureKey: boolean; - parent: string; - parentDataFeatureKey: string; - dataSource: string; - matchLocationName: RegExp; - matchLocationCoordinateMap: string[]; - minZoom: number; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - siteTerrain: string; - }; - export const DISTRIBUTED_MAMMAL_GRID_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - descriptionFromParentDataFeatureKey: boolean; - parent: string; - parentDataFeatureKey: string; - dataSource: string; - matchLocationName: RegExp; - matchLocationCoordinateMap: string[]; - minZoom: number; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - siteTerrain: string; - }; - export const DISTRIBUTED_TICK_PLOT_BOUNDARIES: { - name: string; - nameSingular: string; - type: any; - descriptionFromParentDataFeatureKey: boolean; - parent: string; - parentDataFeatureKey: string; - dataSource: string; - matchLocationName: RegExp; - matchLocationCoordinateMap: string[]; - minZoom: number; - featureShape: string; - style: { - color: string; - dashArray: string; - }; - siteTerrain: string; - }; - export const AQUATIC_SITE_FEATURES: { - name: string; - type: any; - minZoom: number; - }; - export const AQUATIC_BENCHMARKS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_AUTOMATED_INSTRUMENTS: { - name: string; - type: any; - minZoom: number; - parent: string; - }; - export const AQUATIC_OBSERVATIONAL_SAMPLING: { - name: string; - type: any; - minZoom: number; - parent: string; - }; - export const AQUATIC_RIPARIAN_ASSESSMENTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - description: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_WET_DEPOSITION_POINTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_GROUNDWATER_WELLS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - description: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_METEOROLOGICAL_STATIONS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - description: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_DISCHARGE_POINTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_FISH_POINTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_PLANT_TRANSECTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_SEDIMENT_POINTS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_STAFF_GAUGES: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - description: string; - parent: string; - featureShape: string; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_SENSOR_STATIONS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: RegExp; - description: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const AQUATIC_BUOYS: { - name: string; - nameSingular: string; - type: any; - minZoom: number; - dataSource: string; - matchLocationType: string; - parent: string; - featureShape: string; - iconScale: number; - iconSvg: any; - iconShape: string; - siteTerrain: string; - }; - export const SITE_MARKERS: { - name: string; - type: any; - maxZoom: number; - }; - export const TERRESTRIAL_CORE_SITES: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - attributes: { - type: string; - terrain: string; - }; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - iconScale: number; - iconSvg: any; - iconSelectedSvg: any; - iconShape: string; - maxZoom: number; - }; - export const TERRESTRIAL_RELOCATABLE_SITES: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - attributes: { - type: string; - terrain: string; - }; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - iconScale: number; - iconSvg: any; - iconSelectedSvg: any; - iconShape: string; - maxZoom: number; - }; - export const AQUATIC_CORE_SITES: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - attributes: { - type: string; - terrain: string; - }; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - iconScale: number; - iconSvg: any; - iconSelectedSvg: any; - iconShape: string; - maxZoom: number; - }; - export const AQUATIC_RELOCATABLE_SITES: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - attributes: { - type: string; - terrain: string; - }; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - iconScale: number; - iconSvg: any; - iconSelectedSvg: any; - iconShape: string; - maxZoom: number; - }; - export const DECOMMISSIONED_SITES: { - name: string; - nameSingular: string; - type: any; - description: string; - parent: string; - attributes: { - type: string; - terrain: string; - }; - dataSource: string; - primaryIdOnly: boolean; - featureShape: string; - iconScale: number; - iconSvg: any; - iconSelectedSvg: any; - iconShape: string; - maxZoom: number; - }; + export namespace FLIGHT_BOX_BOUNDARIES { + const name_22: string; + export { name_22 as name }; + const nameSingular_2: string; + export { nameSingular_2 as nameSingular }; + const type_2: any; + export { type_2 as type }; + export const minZoom: number; + import dataSource_2 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_2 as dataSource }; + const featureShape_2: string; + export { featureShape_2 as featureShape }; + export namespace style_2 { + const color_22: string; + export { color_22 as color }; + export const dashArray: string; + } + export { style_2 as style }; + } + export namespace AQUATIC_WATERSHEDS { + const name_23: string; + export { name_23 as name }; + const type_3: any; + export { type_3 as type }; + const minZoom_1: number; + export { minZoom_1 as minZoom }; + } + export namespace WATERSHED_BOUNDARIES { + const name_24: string; + export { name_24 as name }; + const nameSingular_3: string; + export { nameSingular_3 as nameSingular }; + const type_4: any; + export { type_4 as type }; + const minZoom_2: number; + export { minZoom_2 as minZoom }; + import dataSource_3 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_3 as dataSource }; + export const parent: string; + const featureShape_3: string; + export { featureShape_3 as featureShape }; + export namespace style_3 { + const color_23: string; + export { color_23 as color }; + const dashArray_1: string; + export { dashArray_1 as dashArray }; + } + export { style_3 as style }; + } + export namespace DRAINAGE_LINES { + const name_25: string; + export { name_25 as name }; + const type_5: any; + export { type_5 as type }; + const minZoom_3: number; + export { minZoom_3 as minZoom }; + import dataSource_4 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_4 as dataSource }; + const parent_1: string; + export { parent_1 as parent }; + const featureShape_4: string; + export { featureShape_4 as featureShape }; + export namespace style_4 { + const color_24: string; + export { color_24 as color }; + } + export { style_4 as style }; + } + export namespace POUR_POINTS { + const name_26: string; + export { name_26 as name }; + const nameSingular_4: string; + export { nameSingular_4 as nameSingular }; + const type_6: any; + export { type_6 as type }; + const minZoom_4: number; + export { minZoom_4 as minZoom }; + import dataSource_5 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_5 as dataSource }; + const parent_2: string; + export { parent_2 as parent }; + const featureShape_5: string; + export { featureShape_5 as featureShape }; + export { iconPourPointSVG as iconSvg }; + import iconShape = KEY; + export { iconShape }; + } + export namespace SAMPLING_BOUNDARIES { + const name_27: string; + export { name_27 as name }; + const nameSingular_5: string; + export { nameSingular_5 as nameSingular }; + const type_7: any; + export { type_7 as type }; + const minZoom_5: number; + export { minZoom_5 as minZoom }; + import dataSource_6 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_6 as dataSource }; + const description_20: string; + export { description_20 as description }; + const parent_3: string; + export { parent_3 as parent }; + const featureShape_6: string; + export { featureShape_6 as featureShape }; + export namespace style_5 { + const color_25: string; + export { color_25 as color }; + const dashArray_2: string; + export { dashArray_2 as dashArray }; + } + export { style_5 as style }; + } + export namespace AQUATIC_REACHES { + const name_28: string; + export { name_28 as name }; + const nameSingular_6: string; + export { nameSingular_6 as nameSingular }; + const type_8: any; + export { type_8 as type }; + const minZoom_6: number; + export { minZoom_6 as minZoom }; + import dataSource_7 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_7 as dataSource }; + const parent_4: string; + export { parent_4 as parent }; + const featureShape_7: string; + export { featureShape_7 as featureShape }; + export namespace style_6 { + const color_26: string; + export { color_26 as color }; + const dashArray_3: string; + export { dashArray_3 as dashArray }; + } + export { style_6 as style }; + } + export namespace TOWER_AIRSHEDS { + const name_29: string; + export { name_29 as name }; + const nameSingular_7: string; + export { nameSingular_7 as nameSingular }; + const type_9: any; + export { type_9 as type }; + const minZoom_7: number; + export { minZoom_7 as minZoom }; + import dataSource_8 = FEATURE_DATA_SOURCES.ARCGIS_ASSETS_API; + export { dataSource_8 as dataSource }; + const parent_5: string; + export { parent_5 as parent }; + const featureShape_8: string; + export { featureShape_8 as featureShape }; + export namespace style_7 { + const color_27: string; + export { color_27 as color }; + const dashArray_4: string; + export { dashArray_4 as dashArray }; + } + export { style_7 as style }; + } + export namespace TERRESTRIAL_SITE_FEATURES { + const name_30: string; + export { name_30 as name }; + const type_10: any; + export { type_10 as type }; + const minZoom_8: number; + export { minZoom_8 as minZoom }; + export const fetchingForFeatures: string[]; + } + export namespace TOWERS { + const name_31: string; + export { name_31 as name }; + const nameSingular_8: string; + export { nameSingular_8 as nameSingular }; + const type_11: any; + export { type_11 as type }; + const minZoom_9: number; + export { minZoom_9 as minZoom }; + import dataSource_9 = FEATURE_DATA_SOURCES.REST_LOCATIONS_API; + export { dataSource_9 as dataSource }; + export const matchLocationType: string; + const parent_6: string; + export { parent_6 as parent }; + const featureShape_9: string; + export { featureShape_9 as featureShape }; + export const iconScale: number; + export { iconTowerSVG as iconSvg }; + import iconShape_1 = KEY; + export { iconShape_1 as iconShape }; + import siteTerrain = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain }; + } + export namespace HUTS { + const name_32: string; + export { name_32 as name }; + const nameSingular_9: string; + export { nameSingular_9 as nameSingular }; + const type_12: any; + export { type_12 as type }; + const minZoom_10: number; + export { minZoom_10 as minZoom }; + import dataSource_10 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_10 as dataSource }; + const matchLocationType_1: string; + export { matchLocationType_1 as matchLocationType }; + const parent_7: string; + export { parent_7 as parent }; + const featureShape_10: string; + export { featureShape_10 as featureShape }; + const iconScale_1: number; + export { iconScale_1 as iconScale }; + export { iconHutSVG as iconSvg }; + import iconShape_2 = KEY; + export { iconShape_2 as iconShape }; + import siteTerrain_1 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_1 as siteTerrain }; + } + export namespace MEGAPITS { + const name_33: string; + export { name_33 as name }; + const nameSingular_10: string; + export { nameSingular_10 as nameSingular }; + const type_13: any; + export { type_13 as type }; + const minZoom_11: number; + export { minZoom_11 as minZoom }; + import dataSource_11 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_11 as dataSource }; + const matchLocationType_2: string; + export { matchLocationType_2 as matchLocationType }; + const parent_8: string; + export { parent_8 as parent }; + const featureShape_11: string; + export { featureShape_11 as featureShape }; + const iconScale_2: number; + export { iconScale_2 as iconScale }; + export { iconMegapitSVG as iconSvg }; + import iconShape_3 = KEY; + export { iconShape_3 as iconShape }; + import siteTerrain_2 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_2 as siteTerrain }; + } + export namespace TOWER_PLOTS { + const name_34: string; + export { name_34 as name }; + const type_14: any; + export { type_14 as type }; + const minZoom_12: number; + export { minZoom_12 as minZoom }; + const description_21: string; + export { description_21 as description }; + const parent_9: string; + export { parent_9 as parent }; + } + export namespace TOWER_PHENOLOGY_PLOTS { + const name_35: string; + export { name_35 as name }; + const nameSingular_11: string; + export { nameSingular_11 as nameSingular }; + const type_15: any; + export { type_15 as type }; + const description_22: string; + export { description_22 as description }; + const parent_10: string; + export { parent_10 as parent }; + import dataSource_12 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_12 as dataSource }; + const matchLocationType_3: string; + export { matchLocationType_3 as matchLocationType }; + const featureShape_12: string; + export { featureShape_12 as featureShape }; + const minZoom_13: number; + export { minZoom_13 as minZoom }; + export const focusZoom: number; + const iconScale_3: number; + export { iconScale_3 as iconScale }; + export { iconTowerPhenologyPlotSVG as iconSvg }; + import iconShape_4 = KEY; + export { iconShape_4 as iconShape }; + import siteTerrain_3 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_3 as siteTerrain }; + } + export namespace TOWER_BASE_PLOTS { + const name_36: string; + export { name_36 as name }; + const nameSingular_12: string; + export { nameSingular_12 as nameSingular }; + const type_16: any; + export { type_16 as type }; + const description_23: string; + export { description_23 as description }; + const parent_11: string; + export { parent_11 as parent }; + import dataSource_13 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_13 as dataSource }; + const matchLocationType_4: string; + export { matchLocationType_4 as matchLocationType }; + const featureShape_13: string; + export { featureShape_13 as featureShape }; + const minZoom_14: number; + export { minZoom_14 as minZoom }; + const focusZoom_1: number; + export { focusZoom_1 as focusZoom }; + export { iconTowerBasePlotSVG as iconSvg }; + import iconShape_5 = KEY; + export { iconShape_5 as iconShape }; + import siteTerrain_4 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_4 as siteTerrain }; + } + export namespace TOWER_SOIL_PLOTS { + const name_37: string; + export { name_37 as name }; + const nameSingular_13: string; + export { nameSingular_13 as nameSingular }; + const type_17: any; + export { type_17 as type }; + import dataSource_14 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_14 as dataSource }; + const matchLocationType_5: string; + export { matchLocationType_5 as matchLocationType }; + const description_24: string; + export { description_24 as description }; + const parent_12: string; + export { parent_12 as parent }; + const featureShape_14: string; + export { featureShape_14 as featureShape }; + const minZoom_15: number; + export { minZoom_15 as minZoom }; + const focusZoom_2: number; + export { focusZoom_2 as focusZoom }; + const iconScale_4: number; + export { iconScale_4 as iconScale }; + export { iconTowerSoilPlotSVG as iconSvg }; + import iconShape_6 = KEY; + export { iconShape_6 as iconShape }; + import siteTerrain_5 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_5 as siteTerrain }; + } + export namespace DISTRIBUTED_PLOTS { + const name_38: string; + export { name_38 as name }; + const type_18: any; + export { type_18 as type }; + const minZoom_16: number; + export { minZoom_16 as minZoom }; + const description_25: string; + export { description_25 as description }; + const parent_13: string; + export { parent_13 as parent }; + } + export namespace DISTRIBUTED_BIRD_GRIDS { + const name_39: string; + export { name_39 as name }; + const nameSingular_14: string; + export { nameSingular_14 as nameSingular }; + const type_19: any; + export { type_19 as type }; + const description_26: string; + export { description_26 as description }; + const parent_14: string; + export { parent_14 as parent }; + import dataSource_15 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_15 as dataSource }; + const matchLocationType_6: string; + export { matchLocationType_6 as matchLocationType }; + const featureShape_15: string; + export { featureShape_15 as featureShape }; + const iconScale_5: number; + export { iconScale_5 as iconScale }; + const focusZoom_3: number; + export { focusZoom_3 as focusZoom }; + export { iconDistributedBirdGridSVG as iconSvg }; + import iconShape_7 = KEY; + export { iconShape_7 as iconShape }; + import siteTerrain_6 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_6 as siteTerrain }; + } + export namespace DISTRIBUTED_MAMMAL_GRIDS { + const name_40: string; + export { name_40 as name }; + const nameSingular_15: string; + export { nameSingular_15 as nameSingular }; + const type_20: any; + export { type_20 as type }; + const description_27: string; + export { description_27 as description }; + const parent_15: string; + export { parent_15 as parent }; + import dataSource_16 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_16 as dataSource }; + const matchLocationType_7: string; + export { matchLocationType_7 as matchLocationType }; + const featureShape_16: string; + export { featureShape_16 as featureShape }; + const iconScale_6: number; + export { iconScale_6 as iconScale }; + const focusZoom_4: number; + export { focusZoom_4 as focusZoom }; + export { iconDistributedMammalGridSVG as iconSvg }; + import iconShape_8 = KEY; + export { iconShape_8 as iconShape }; + import siteTerrain_7 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_7 as siteTerrain }; + } + export namespace DISTRIBUTED_BASE_PLOTS { + const name_41: string; + export { name_41 as name }; + const nameSingular_16: string; + export { nameSingular_16 as nameSingular }; + const type_21: any; + export { type_21 as type }; + const description_28: string; + export { description_28 as description }; + const parent_16: string; + export { parent_16 as parent }; + const featureShape_17: string; + export { featureShape_17 as featureShape }; + import dataSource_17 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_17 as dataSource }; + const matchLocationType_8: string; + export { matchLocationType_8 as matchLocationType }; + const iconScale_7: number; + export { iconScale_7 as iconScale }; + const focusZoom_5: number; + export { focusZoom_5 as focusZoom }; + export { iconDistributedBasePlotSVG as iconSvg }; + import iconShape_9 = KEY; + export { iconShape_9 as iconShape }; + import siteTerrain_8 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_8 as siteTerrain }; + } + export namespace DISTRIBUTED_TICK_PLOTS { + const name_42: string; + export { name_42 as name }; + const nameSingular_17: string; + export { nameSingular_17 as nameSingular }; + const type_22: any; + export { type_22 as type }; + const description_29: string; + export { description_29 as description }; + const parent_17: string; + export { parent_17 as parent }; + import dataSource_18 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_18 as dataSource }; + const matchLocationType_9: string; + export { matchLocationType_9 as matchLocationType }; + const featureShape_18: string; + export { featureShape_18 as featureShape }; + const iconScale_8: number; + export { iconScale_8 as iconScale }; + const focusZoom_6: number; + export { focusZoom_6 as focusZoom }; + export { iconDistributedTickPlotSVG as iconSvg }; + import iconShape_10 = KEY; + export { iconShape_10 as iconShape }; + import siteTerrain_9 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_9 as siteTerrain }; + } + export namespace DISTRIBUTED_MOSQUITO_POINTS { + const name_43: string; + export { name_43 as name }; + const nameSingular_18: string; + export { nameSingular_18 as nameSingular }; + const type_23: any; + export { type_23 as type }; + const description_30: string; + export { description_30 as description }; + const parent_18: string; + export { parent_18 as parent }; + import dataSource_19 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_19 as dataSource }; + const matchLocationType_10: string; + export { matchLocationType_10 as matchLocationType }; + export { iconDistributedMosquitoPointSVG as iconSvg }; + import iconShape_11 = KEY; + export { iconShape_11 as iconShape }; + const featureShape_19: string; + export { featureShape_19 as featureShape }; + const focusZoom_7: number; + export { focusZoom_7 as focusZoom }; + import siteTerrain_10 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_10 as siteTerrain }; + } + export namespace PLOT_BOUNDARIES { + const name_44: string; + export { name_44 as name }; + const type_24: any; + export { type_24 as type }; + const minZoom_17: number; + export { minZoom_17 as minZoom }; + const description_31: string; + export { description_31 as description }; + const parent_19: string; + export { parent_19 as parent }; + } + export namespace TOWER_PHENOLOGY_PLOT_BOUNDARIES { + const name_45: string; + export { name_45 as name }; + const nameSingular_19: string; + export { nameSingular_19 as nameSingular }; + const type_25: any; + export { type_25 as type }; + export const descriptionFromParentDataFeatureKey: boolean; + const parent_20: string; + export { parent_20 as parent }; + export const parentDataFeatureKey: string; + import dataSource_20 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_20 as dataSource }; + export const matchLocationName: RegExp; + export const matchLocationCoordinateMap: string[]; + const minZoom_18: number; + export { minZoom_18 as minZoom }; + const featureShape_20: string; + export { featureShape_20 as featureShape }; + export namespace style_8 { + const color_28: string; + export { color_28 as color }; + const dashArray_5: string; + export { dashArray_5 as dashArray }; + } + export { style_8 as style }; + import siteTerrain_11 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_11 as siteTerrain }; + } + export namespace TOWER_SOIL_PLOT_BOUNDARIES { + const name_46: string; + export { name_46 as name }; + const nameSingular_20: string; + export { nameSingular_20 as nameSingular }; + const type_26: any; + export { type_26 as type }; + const descriptionFromParentDataFeatureKey_1: boolean; + export { descriptionFromParentDataFeatureKey_1 as descriptionFromParentDataFeatureKey }; + const parent_21: string; + export { parent_21 as parent }; + const parentDataFeatureKey_1: string; + export { parentDataFeatureKey_1 as parentDataFeatureKey }; + const minZoom_19: number; + export { minZoom_19 as minZoom }; + const featureShape_21: string; + export { featureShape_21 as featureShape }; + export namespace style_9 { + const color_29: string; + export { color_29 as color }; + const dashArray_6: string; + export { dashArray_6 as dashArray }; + } + export { style_9 as style }; + } + export namespace DISTRIBUTED_BIRD_GRID_BOUNDARIES { + const name_47: string; + export { name_47 as name }; + const nameSingular_21: string; + export { nameSingular_21 as nameSingular }; + const type_27: any; + export { type_27 as type }; + const descriptionFromParentDataFeatureKey_2: boolean; + export { descriptionFromParentDataFeatureKey_2 as descriptionFromParentDataFeatureKey }; + const parent_22: string; + export { parent_22 as parent }; + const parentDataFeatureKey_2: string; + export { parentDataFeatureKey_2 as parentDataFeatureKey }; + import dataSource_21 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_21 as dataSource }; + const matchLocationName_1: RegExp; + export { matchLocationName_1 as matchLocationName }; + const matchLocationCoordinateMap_1: string[]; + export { matchLocationCoordinateMap_1 as matchLocationCoordinateMap }; + const minZoom_20: number; + export { minZoom_20 as minZoom }; + const featureShape_22: string; + export { featureShape_22 as featureShape }; + export namespace style_10 { + const color_30: string; + export { color_30 as color }; + const dashArray_7: string; + export { dashArray_7 as dashArray }; + } + export { style_10 as style }; + import siteTerrain_12 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_12 as siteTerrain }; + } + export namespace DISTRIBUTED_MAMMAL_GRID_BOUNDARIES { + const name_48: string; + export { name_48 as name }; + const nameSingular_22: string; + export { nameSingular_22 as nameSingular }; + const type_28: any; + export { type_28 as type }; + const descriptionFromParentDataFeatureKey_3: boolean; + export { descriptionFromParentDataFeatureKey_3 as descriptionFromParentDataFeatureKey }; + const parent_23: string; + export { parent_23 as parent }; + const parentDataFeatureKey_3: string; + export { parentDataFeatureKey_3 as parentDataFeatureKey }; + import dataSource_22 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_22 as dataSource }; + const matchLocationName_2: RegExp; + export { matchLocationName_2 as matchLocationName }; + const matchLocationCoordinateMap_2: string[]; + export { matchLocationCoordinateMap_2 as matchLocationCoordinateMap }; + const minZoom_21: number; + export { minZoom_21 as minZoom }; + const featureShape_23: string; + export { featureShape_23 as featureShape }; + export namespace style_11 { + const color_31: string; + export { color_31 as color }; + const dashArray_8: string; + export { dashArray_8 as dashArray }; + } + export { style_11 as style }; + import siteTerrain_13 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_13 as siteTerrain }; + } + export namespace DISTRIBUTED_TICK_PLOT_BOUNDARIES { + const name_49: string; + export { name_49 as name }; + const nameSingular_23: string; + export { nameSingular_23 as nameSingular }; + const type_29: any; + export { type_29 as type }; + const descriptionFromParentDataFeatureKey_4: boolean; + export { descriptionFromParentDataFeatureKey_4 as descriptionFromParentDataFeatureKey }; + const parent_24: string; + export { parent_24 as parent }; + const parentDataFeatureKey_4: string; + export { parentDataFeatureKey_4 as parentDataFeatureKey }; + import dataSource_23 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_23 as dataSource }; + const matchLocationName_3: RegExp; + export { matchLocationName_3 as matchLocationName }; + const matchLocationCoordinateMap_3: string[]; + export { matchLocationCoordinateMap_3 as matchLocationCoordinateMap }; + const minZoom_22: number; + export { minZoom_22 as minZoom }; + const featureShape_24: string; + export { featureShape_24 as featureShape }; + export namespace style_12 { + const color_32: string; + export { color_32 as color }; + const dashArray_9: string; + export { dashArray_9 as dashArray }; + } + export { style_12 as style }; + import siteTerrain_14 = SITE_TERRAINS.TERRESTRIAL; + export { siteTerrain_14 as siteTerrain }; + } + export namespace AQUATIC_SITE_FEATURES { + const name_50: string; + export { name_50 as name }; + const type_30: any; + export { type_30 as type }; + const minZoom_23: number; + export { minZoom_23 as minZoom }; + } + export namespace AQUATIC_BENCHMARKS { + const name_51: string; + export { name_51 as name }; + const nameSingular_24: string; + export { nameSingular_24 as nameSingular }; + const type_31: any; + export { type_31 as type }; + const minZoom_24: number; + export { minZoom_24 as minZoom }; + import dataSource_24 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_24 as dataSource }; + const matchLocationType_11: string; + export { matchLocationType_11 as matchLocationType }; + const parent_25: string; + export { parent_25 as parent }; + const featureShape_25: string; + export { featureShape_25 as featureShape }; + const iconScale_9: number; + export { iconScale_9 as iconScale }; + export { iconBenchmarkSVG as iconSvg }; + import iconShape_12 = KEY; + export { iconShape_12 as iconShape }; + import siteTerrain_15 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_15 as siteTerrain }; + } + export namespace AQUATIC_AUTOMATED_INSTRUMENTS { + const name_52: string; + export { name_52 as name }; + const type_32: any; + export { type_32 as type }; + const minZoom_25: number; + export { minZoom_25 as minZoom }; + const parent_26: string; + export { parent_26 as parent }; + } + export namespace AQUATIC_OBSERVATIONAL_SAMPLING { + const name_53: string; + export { name_53 as name }; + const type_33: any; + export { type_33 as type }; + const minZoom_26: number; + export { minZoom_26 as minZoom }; + const parent_27: string; + export { parent_27 as parent }; + } + export namespace AQUATIC_RIPARIAN_ASSESSMENTS { + const name_54: string; + export { name_54 as name }; + const nameSingular_25: string; + export { nameSingular_25 as nameSingular }; + const type_34: any; + export { type_34 as type }; + const minZoom_27: number; + export { minZoom_27 as minZoom }; + import dataSource_25 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_25 as dataSource }; + const matchLocationType_12: string; + export { matchLocationType_12 as matchLocationType }; + const description_32: string; + export { description_32 as description }; + const parent_28: string; + export { parent_28 as parent }; + const featureShape_26: string; + export { featureShape_26 as featureShape }; + export { iconRiparianAssessmentSVG as iconSvg }; + import iconShape_13 = KEY; + export { iconShape_13 as iconShape }; + import siteTerrain_16 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_16 as siteTerrain }; + } + export namespace AQUATIC_WET_DEPOSITION_POINTS { + const name_55: string; + export { name_55 as name }; + const nameSingular_26: string; + export { nameSingular_26 as nameSingular }; + const type_35: any; + export { type_35 as type }; + const minZoom_28: number; + export { minZoom_28 as minZoom }; + import dataSource_26 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_26 as dataSource }; + const matchLocationType_13: string; + export { matchLocationType_13 as matchLocationType }; + const parent_29: string; + export { parent_29 as parent }; + const featureShape_27: string; + export { featureShape_27 as featureShape }; + const iconScale_10: number; + export { iconScale_10 as iconScale }; + export { iconWetDepositionPointSVG as iconSvg }; + import iconShape_14 = KEY; + export { iconShape_14 as iconShape }; + import siteTerrain_17 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_17 as siteTerrain }; + } + export namespace AQUATIC_GROUNDWATER_WELLS { + const name_56: string; + export { name_56 as name }; + const nameSingular_27: string; + export { nameSingular_27 as nameSingular }; + const type_36: any; + export { type_36 as type }; + const minZoom_29: number; + export { minZoom_29 as minZoom }; + import dataSource_27 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_27 as dataSource }; + const matchLocationType_14: string; + export { matchLocationType_14 as matchLocationType }; + const description_33: string; + export { description_33 as description }; + const parent_30: string; + export { parent_30 as parent }; + const featureShape_28: string; + export { featureShape_28 as featureShape }; + const iconScale_11: number; + export { iconScale_11 as iconScale }; + export { iconGroundwaterWellSVG as iconSvg }; + import iconShape_15 = KEY; + export { iconShape_15 as iconShape }; + import siteTerrain_18 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_18 as siteTerrain }; + } + export namespace AQUATIC_METEOROLOGICAL_STATIONS { + const name_57: string; + export { name_57 as name }; + const nameSingular_28: string; + export { nameSingular_28 as nameSingular }; + const type_37: any; + export { type_37 as type }; + const minZoom_30: number; + export { minZoom_30 as minZoom }; + import dataSource_28 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_28 as dataSource }; + const matchLocationType_15: string; + export { matchLocationType_15 as matchLocationType }; + const description_34: string; + export { description_34 as description }; + const parent_31: string; + export { parent_31 as parent }; + const featureShape_29: string; + export { featureShape_29 as featureShape }; + const iconScale_12: number; + export { iconScale_12 as iconScale }; + export { iconMeteorologicalStationSVG as iconSvg }; + import iconShape_16 = KEY; + export { iconShape_16 as iconShape }; + import siteTerrain_19 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_19 as siteTerrain }; + } + export namespace AQUATIC_DISCHARGE_POINTS { + const name_58: string; + export { name_58 as name }; + const nameSingular_29: string; + export { nameSingular_29 as nameSingular }; + const type_38: any; + export { type_38 as type }; + const minZoom_31: number; + export { minZoom_31 as minZoom }; + import dataSource_29 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_29 as dataSource }; + const matchLocationType_16: string; + export { matchLocationType_16 as matchLocationType }; + const parent_32: string; + export { parent_32 as parent }; + const featureShape_30: string; + export { featureShape_30 as featureShape }; + export { iconDischargePointSVG as iconSvg }; + import iconShape_17 = KEY; + export { iconShape_17 as iconShape }; + import siteTerrain_20 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_20 as siteTerrain }; + } + export namespace AQUATIC_FISH_POINTS { + const name_59: string; + export { name_59 as name }; + const nameSingular_30: string; + export { nameSingular_30 as nameSingular }; + const type_39: any; + export { type_39 as type }; + const minZoom_32: number; + export { minZoom_32 as minZoom }; + import dataSource_30 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_30 as dataSource }; + const matchLocationType_17: string; + export { matchLocationType_17 as matchLocationType }; + const parent_33: string; + export { parent_33 as parent }; + const featureShape_31: string; + export { featureShape_31 as featureShape }; + export { iconFishPointSVG as iconSvg }; + import iconShape_18 = KEY; + export { iconShape_18 as iconShape }; + import siteTerrain_21 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_21 as siteTerrain }; + } + export namespace AQUATIC_PLANT_TRANSECTS { + const name_60: string; + export { name_60 as name }; + const nameSingular_31: string; + export { nameSingular_31 as nameSingular }; + const type_40: any; + export { type_40 as type }; + const minZoom_33: number; + export { minZoom_33 as minZoom }; + import dataSource_31 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_31 as dataSource }; + const matchLocationType_18: string; + export { matchLocationType_18 as matchLocationType }; + const parent_34: string; + export { parent_34 as parent }; + const featureShape_32: string; + export { featureShape_32 as featureShape }; + const iconScale_13: number; + export { iconScale_13 as iconScale }; + export { iconPlantTransectSVG as iconSvg }; + import iconShape_19 = KEY; + export { iconShape_19 as iconShape }; + import siteTerrain_22 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_22 as siteTerrain }; + } + export namespace AQUATIC_SEDIMENT_POINTS { + const name_61: string; + export { name_61 as name }; + const nameSingular_32: string; + export { nameSingular_32 as nameSingular }; + const type_41: any; + export { type_41 as type }; + const minZoom_34: number; + export { minZoom_34 as minZoom }; + import dataSource_32 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_32 as dataSource }; + const matchLocationType_19: string; + export { matchLocationType_19 as matchLocationType }; + const parent_35: string; + export { parent_35 as parent }; + const featureShape_33: string; + export { featureShape_33 as featureShape }; + export { iconSedimentPointSVG as iconSvg }; + import iconShape_20 = KEY; + export { iconShape_20 as iconShape }; + import siteTerrain_23 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_23 as siteTerrain }; + } + export namespace AQUATIC_STAFF_GAUGES { + const name_62: string; + export { name_62 as name }; + const nameSingular_33: string; + export { nameSingular_33 as nameSingular }; + const type_42: any; + export { type_42 as type }; + const minZoom_35: number; + export { minZoom_35 as minZoom }; + import dataSource_33 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_33 as dataSource }; + const matchLocationType_20: string; + export { matchLocationType_20 as matchLocationType }; + const description_35: string; + export { description_35 as description }; + const parent_36: string; + export { parent_36 as parent }; + const featureShape_34: string; + export { featureShape_34 as featureShape }; + export { iconStaffGaugeSVG as iconSvg }; + import iconShape_21 = KEY; + export { iconShape_21 as iconShape }; + import siteTerrain_24 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_24 as siteTerrain }; + } + export namespace AQUATIC_SENSOR_STATIONS { + const name_63: string; + export { name_63 as name }; + const nameSingular_34: string; + export { nameSingular_34 as nameSingular }; + const type_43: any; + export { type_43 as type }; + const minZoom_36: number; + export { minZoom_36 as minZoom }; + import dataSource_34 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_34 as dataSource }; + const matchLocationType_21: RegExp; + export { matchLocationType_21 as matchLocationType }; + const description_36: string; + export { description_36 as description }; + const parent_37: string; + export { parent_37 as parent }; + const featureShape_35: string; + export { featureShape_35 as featureShape }; + const iconScale_14: number; + export { iconScale_14 as iconScale }; + export { iconSensorStationSVG as iconSvg }; + import iconShape_22 = KEY; + export { iconShape_22 as iconShape }; + import siteTerrain_25 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_25 as siteTerrain }; + } + export namespace AQUATIC_BUOYS { + const name_64: string; + export { name_64 as name }; + const nameSingular_35: string; + export { nameSingular_35 as nameSingular }; + const type_44: any; + export { type_44 as type }; + const minZoom_37: number; + export { minZoom_37 as minZoom }; + import dataSource_35 = FEATURE_DATA_SOURCES.GRAPHQL_LOCATIONS_API; + export { dataSource_35 as dataSource }; + const matchLocationType_22: string; + export { matchLocationType_22 as matchLocationType }; + const parent_38: string; + export { parent_38 as parent }; + const featureShape_36: string; + export { featureShape_36 as featureShape }; + const iconScale_15: number; + export { iconScale_15 as iconScale }; + export { iconBuoySVG as iconSvg }; + import iconShape_23 = KEY; + export { iconShape_23 as iconShape }; + import siteTerrain_26 = SITE_TERRAINS.AQUATIC; + export { siteTerrain_26 as siteTerrain }; + } + export namespace SITE_MARKERS { + const name_65: string; + export { name_65 as name }; + const type_45: any; + export { type_45 as type }; + export const maxZoom: number; + } + export namespace TERRESTRIAL_CORE_SITES { + const name_66: string; + export { name_66 as name }; + const nameSingular_36: string; + export { nameSingular_36 as nameSingular }; + const type_46: any; + export { type_46 as type }; + const description_37: string; + export { description_37 as description }; + const parent_39: string; + export { parent_39 as parent }; + export namespace attributes { + const type_47: string; + export { type_47 as type }; + export const terrain: string; + } + import dataSource_36 = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource_36 as dataSource }; + const primaryIdOnly_2: boolean; + export { primaryIdOnly_2 as primaryIdOnly }; + const featureShape_37: string; + export { featureShape_37 as featureShape }; + const iconScale_16: number; + export { iconScale_16 as iconScale }; + export { iconSiteCoreTerrestrialSVG as iconSvg }; + export { iconSiteCoreTerrestrialSelectedSVG as iconSelectedSvg }; + import iconShape_24 = KEY; + export { iconShape_24 as iconShape }; + const maxZoom_1: number; + export { maxZoom_1 as maxZoom }; + } + export namespace TERRESTRIAL_RELOCATABLE_SITES { + const name_67: string; + export { name_67 as name }; + const nameSingular_37: string; + export { nameSingular_37 as nameSingular }; + const type_48: any; + export { type_48 as type }; + const description_38: string; + export { description_38 as description }; + const parent_40: string; + export { parent_40 as parent }; + export namespace attributes_1 { + const type_49: string; + export { type_49 as type }; + const terrain_1: string; + export { terrain_1 as terrain }; + } + export { attributes_1 as attributes }; + import dataSource_37 = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource_37 as dataSource }; + const primaryIdOnly_3: boolean; + export { primaryIdOnly_3 as primaryIdOnly }; + const featureShape_38: string; + export { featureShape_38 as featureShape }; + const iconScale_17: number; + export { iconScale_17 as iconScale }; + export { iconSiteRelocatableTerrestrialSVG as iconSvg }; + export { iconSiteRelocatableTerrestrialSelectedSVG as iconSelectedSvg }; + import iconShape_25 = KEY; + export { iconShape_25 as iconShape }; + const maxZoom_2: number; + export { maxZoom_2 as maxZoom }; + } + export namespace AQUATIC_CORE_SITES { + const name_68: string; + export { name_68 as name }; + const nameSingular_38: string; + export { nameSingular_38 as nameSingular }; + const type_50: any; + export { type_50 as type }; + const description_39: string; + export { description_39 as description }; + const parent_41: string; + export { parent_41 as parent }; + export namespace attributes_2 { + const type_51: string; + export { type_51 as type }; + const terrain_2: string; + export { terrain_2 as terrain }; + } + export { attributes_2 as attributes }; + import dataSource_38 = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource_38 as dataSource }; + const primaryIdOnly_4: boolean; + export { primaryIdOnly_4 as primaryIdOnly }; + const featureShape_39: string; + export { featureShape_39 as featureShape }; + const iconScale_18: number; + export { iconScale_18 as iconScale }; + export { iconSiteCoreAquaticSVG as iconSvg }; + export { iconSiteCoreAquaticSelectedSVG as iconSelectedSvg }; + import iconShape_26 = KEY; + export { iconShape_26 as iconShape }; + const maxZoom_3: number; + export { maxZoom_3 as maxZoom }; + } + export namespace AQUATIC_RELOCATABLE_SITES { + const name_69: string; + export { name_69 as name }; + const nameSingular_39: string; + export { nameSingular_39 as nameSingular }; + const type_52: any; + export { type_52 as type }; + const description_40: string; + export { description_40 as description }; + const parent_42: string; + export { parent_42 as parent }; + export namespace attributes_3 { + const type_53: string; + export { type_53 as type }; + const terrain_3: string; + export { terrain_3 as terrain }; + } + export { attributes_3 as attributes }; + import dataSource_39 = FEATURE_DATA_SOURCES.NEON_CONTEXT; + export { dataSource_39 as dataSource }; + const primaryIdOnly_5: boolean; + export { primaryIdOnly_5 as primaryIdOnly }; + const featureShape_40: string; + export { featureShape_40 as featureShape }; + const iconScale_19: number; + export { iconScale_19 as iconScale }; + export { iconSiteRelocatableAquaticSVG as iconSvg }; + export { iconSiteRelocatableAquaticSelectedSVG as iconSelectedSvg }; + import iconShape_27 = KEY; + export { iconShape_27 as iconShape }; + const maxZoom_4: number; + export { maxZoom_4 as maxZoom }; + } + export namespace DECOMMISSIONED_SITES { + const name_70: string; + export { name_70 as name }; + const nameSingular_40: string; + export { nameSingular_40 as nameSingular }; + const type_54: any; + export { type_54 as type }; + const description_41: string; + export { description_41 as description }; + const parent_43: string; + export { parent_43 as parent }; + export namespace attributes_4 { + const type_55: string; + export { type_55 as type }; + const terrain_4: string; + export { terrain_4 as terrain }; + } + export { attributes_4 as attributes }; + import dataSource_40 = FEATURE_DATA_SOURCES.MANUAL_LOCATIONS; + export { dataSource_40 as dataSource }; + const primaryIdOnly_6: boolean; + export { primaryIdOnly_6 as primaryIdOnly }; + const featureShape_41: string; + export { featureShape_41 as featureShape }; + const iconScale_20: number; + export { iconScale_20 as iconScale }; + export { iconSiteDecommissionedSVG as iconSvg }; + export { iconSiteDecommissionedSVG as iconSelectedSvg }; + import iconShape_28 = KEY; + export { iconShape_28 as iconShape }; + const maxZoom_5: number; + export { maxZoom_5 as maxZoom }; + } } export namespace GRAPHQL_LOCATIONS_API_CONSTANTS { export { FEATURES_TO_MINZOOM_MAP }; export { MINZOOM_TO_FEATURES_MAP }; } export namespace BOUNDARY_COLORS { - export const partialSelected: string; - export const totalSelected: string; - export const hover: string; + const partialSelected: string; + const totalSelected: string; + const hover: string; } export function calculateFeatureAvailability(state: any): any; export function getHref(key: any, arg?: any): string; export namespace BASE_LAYERS { - export namespace NATGEO_WORLD_MAP { - export const title: string; - export const shortAttribution: string; - export const fullAttribution: string; - export const url: string; + namespace NATGEO_WORLD_MAP { + const title: string; + const shortAttribution: string; + const fullAttribution: string; + const url: string; } - export namespace WORLD_IMAGERY { + namespace WORLD_IMAGERY { const title_1: string; export { title_1 as title }; const shortAttribution_1: string; @@ -1144,7 +1648,7 @@ export namespace BASE_LAYERS { const url_1: string; export { url_1 as url }; } - export namespace WORLD_STREET_MAP { + namespace WORLD_STREET_MAP { const title_2: string; export { title_2 as title }; const shortAttribution_2: string; @@ -1154,7 +1658,7 @@ export namespace BASE_LAYERS { const url_2: string; export { url_2 as url }; } - export namespace WORLD_TOPO_MAP { + namespace WORLD_TOPO_MAP { const title_3: string; export { title_3 as title }; const shortAttribution_3: string; @@ -1167,27 +1671,27 @@ export namespace BASE_LAYERS { } export const BASE_LAYERS_BY_TITLE: {}; export namespace OVERLAY_GROUPS { - export namespace NLCD { + namespace NLCD { const title_4: string; export { title_4 as title }; - const description_20: string; - export { description_20 as description }; + const description_42: string; + export { description_42 as description }; export namespace commonProps { - export const format: string; - export const transparent: boolean; + const format: string; + const transparent: boolean; } } } export const OVERLAY_GROUPS_BY_TITLE: {}; export namespace OVERLAYS { - export namespace LAND_COVER { + namespace LAND_COVER { export const group: any; const title_5: string; export { title_5 as title }; - const description_21: string; - export { description_21 as description }; + const description_43: string; + export { description_43 as description }; export namespace commonProps_1 { - export const attribution: string; + const attribution: string; } export { commonProps_1 as commonProps }; export { NLCD_CLASSES as legend }; @@ -1200,13 +1704,13 @@ export namespace OVERLAYS { }; }[]; } - export namespace IMPERVIOUS { + namespace IMPERVIOUS { const group_1: any; export { group_1 as group }; const title_6: string; export { title_6 as title }; - const description_22: string; - export { description_22 as description }; + const description_44: string; + export { description_44 as description }; export namespace commonProps_2 { const attribution_1: string; export { attribution_1 as attribution }; @@ -1276,9 +1780,9 @@ export namespace OVERLAYS { } } export namespace DEFAULT_STATE { - export namespace filters { - export namespace features { - export const available: any; + namespace filters { + namespace features { + const available: any; } } } @@ -1293,12 +1797,12 @@ export namespace SITE_MAP_PROP_TYPES { export const tableFullHeight: PropTypes.Requireable; export const location: PropTypes.Requireable; export const selection: PropTypes.Requireable; - export const selectedItems: PropTypes.Requireable[]>; - export const validItems: PropTypes.Requireable[]>; + export const selectedItems: PropTypes.Requireable<(string | null | undefined)[]>; + export const validItems: PropTypes.Requireable<(string | null | undefined)[]>; export { SelectionLimitPropType as selectionLimit }; export const onSelectionChange: PropTypes.Requireable<(...args: any[]) => any>; export const search: PropTypes.Requireable; - export const features: PropTypes.Requireable[]>; + export const features: PropTypes.Requireable<(string | null | undefined)[]>; export const manualLocationData: PropTypes.Requireable<(PropTypes.InferProps<{ manualLocationType: PropTypes.Validator; }> | null | undefined)[]>; @@ -1340,7 +1844,7 @@ export namespace SITE_MAP_DEFAULT_PROPS { export function getZoomedIcon(featureKey?: any, zoom?: number, highlight?: string, selection?: string): any; export function getZoomedIcons(zoom: any): {}; export function getPhantomLeafletMap(state: any): any; -export function mapIsAtFocusLocation(state?: {}): boolean; +export function mapIsAtFocusLocation(state?: {}): any; export function getMapStateForFocusLocation(state?: {}): any; export function findCentroid(coords?: any[]): any[] | null; export function getMapStateForManualLocationData(state: any): any; diff --git a/lib/components/SiteMap/SiteMapUtils.js b/lib/components/SiteMap/SiteMapUtils.js index 9456682a..3c69ebd8 100644 --- a/lib/components/SiteMap/SiteMapUtils.js +++ b/lib/components/SiteMap/SiteMapUtils.js @@ -13,6 +13,8 @@ var _leaflet = _interopRequireDefault(require("leaflet")); var _Theme = require("../Theme/Theme"); +var _RouteService = _interopRequireDefault(require("../../service/RouteService")); + var _iconPlaceholder = _interopRequireDefault(require("./svg/icon-placeholder.svg")); var _iconShapeCircleShadow = _interopRequireDefault(require("./svg/icon-shape-circle-shadow.svg")); @@ -1354,7 +1356,8 @@ exports.calculateFeatureAvailability = calculateFeatureAvailability; var getHref = function getHref(key) { var arg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; - var EXPLORE_DATA_PRODUCTS_BASE = 'https://data.neonscience.org/data-products/explore'; + + var EXPLORE_DATA_PRODUCTS_BASE = _RouteService.default.getDataProductExplorePath(); if ((arg || '').length === 0) { return '#'; @@ -1371,10 +1374,10 @@ var getHref = function getHref(key) { return "".concat(EXPLORE_DATA_PRODUCTS_BASE, "?domain=").concat(arg); case 'SITE_DETAILS': - return "https://www.neonscience.org/field-sites/".concat(arg); + return _RouteService.default.getFieldSiteDetailPath(arg); case 'DOMAIN_DETAILS': - return "https://www.neonscience.org/domains/".concat(arg); + return _RouteService.default.getDomainDetailPath(arg); default: return '#'; diff --git a/lib/components/Theme/Theme.d.ts b/lib/components/Theme/Theme.d.ts index e2dfa62e..d7103001 100644 --- a/lib/components/Theme/Theme.d.ts +++ b/lib/components/Theme/Theme.d.ts @@ -1,5 +1,5 @@ export namespace COLORS { - export const NEON_BLUE: { + const NEON_BLUE: { 50: string; 100: string; 200: string; @@ -11,7 +11,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const LIGHT_BLUE: { + const LIGHT_BLUE: { 50: string; 100: string; 200: string; @@ -23,7 +23,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const GOLD: { + const GOLD: { 50: string; 100: string; 200: string; @@ -35,7 +35,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const BROWN: { + const BROWN: { 50: string; 100: string; 200: string; @@ -47,7 +47,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const GREEN: { + const GREEN: { 50: string; 100: string; 200: string; @@ -59,7 +59,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const RED: { + const RED: { 50: string; 100: string; 200: string; @@ -71,7 +71,7 @@ export namespace COLORS { 800: string; 900: string; }; - export const GREY: { + const GREY: { 50: string; 100: string; 200: string; diff --git a/lib/components/TimeSeriesViewer/TimeSeriesViewerContainer.js b/lib/components/TimeSeriesViewer/TimeSeriesViewerContainer.js index 29b1ac75..61883220 100644 --- a/lib/components/TimeSeriesViewer/TimeSeriesViewerContainer.js +++ b/lib/components/TimeSeriesViewer/TimeSeriesViewerContainer.js @@ -50,10 +50,10 @@ var _Timeline = _interopRequireDefault(require("@material-ui/icons/Timeline")); var _BorderInner = _interopRequireDefault(require("@material-ui/icons/BorderInner")); -var _NeonEnvironment = _interopRequireDefault(require("../NeonEnvironment/NeonEnvironment")); - var _Theme = _interopRequireWildcard(require("../Theme/Theme")); +var _RouteService = _interopRequireDefault(require("../../service/RouteService")); + var _TimeSeriesViewerContext = _interopRequireWildcard(require("./TimeSeriesViewerContext")); var _TimeSeriesViewerSites = _interopRequireDefault(require("./TimeSeriesViewerSites")); @@ -251,7 +251,7 @@ function TimeSeriesViewerSummary() { } }; // Product - var productHref = "".concat(_NeonEnvironment.default.getHost(), "/data-products/").concat(state.product.productCode); + var productHref = _RouteService.default.getProductDetailPath(state.product.productCode); var productSummaryTitle = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Typography.default, { variant: "h6" diff --git a/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.d.ts b/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.d.ts index bfe231d6..97029070 100644 --- a/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.d.ts +++ b/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.d.ts @@ -1,12 +1,12 @@ export namespace TIME_SERIES_VIEWER_STATUS { - export const INIT_PRODUCT: string; - export const LOADING_META: string; - export const READY_FOR_DATA: string; - export const LOADING_DATA: string; - export const ERROR: string; - export const WARNING: string; - export const READY_FOR_SERIES: string; - export const READY: string; + const INIT_PRODUCT: string; + const LOADING_META: string; + const READY_FOR_DATA: string; + const LOADING_DATA: string; + const ERROR: string; + const WARNING: string; + const READY_FOR_SERIES: string; + const READY: string; } export namespace TIME_SERIES_VIEWER_STATUS_TITLES { const INIT_PRODUCT_1: string; @@ -25,14 +25,14 @@ export namespace TIME_SERIES_VIEWER_STATUS_TITLES { export { READY_1 as READY }; } export namespace Y_AXIS_RANGE_MODES { - export const CENTERED: string; - export const FROM_ZERO: string; - export const CUSTOM: string; + const CENTERED: string; + const FROM_ZERO: string; + const CUSTOM: string; } export namespace Y_AXIS_RANGE_MODE_DETAILS { export namespace CENTERED_1 { - export const name: string; - export const description: string; + const name: string; + const description: string; } export { CENTERED_1 as CENTERED }; export namespace FROM_ZERO_1 { @@ -51,19 +51,19 @@ export namespace Y_AXIS_RANGE_MODE_DETAILS { export { CUSTOM_1 as CUSTOM }; } export namespace TabComponentPropTypes { - export const setSelectedTab: PropTypes.Validator<(...args: any[]) => any>; - export const TAB_IDS: PropTypes.Validator<{ - [x: string]: import("../../types/core").Nullable; + const setSelectedTab: PropTypes.Validator<(...args: any[]) => any>; + const TAB_IDS: PropTypes.Validator<{ + [x: string]: string | null | undefined; }>; } export namespace DEFAULT_STATE { - import mode = DEFAULT; + import mode = VIEWER_MODE.DEFAULT; export { mode }; - import status = INIT_PRODUCT; + import status = TIME_SERIES_VIEWER_STATUS.INIT_PRODUCT; export { status }; export const displayError: null; export namespace fetchProduct { - import status_1 = AWAITING_CALL; + import status_1 = FETCH_STATUS.AWAITING_CALL; export { status_1 as status }; export const error: null; } @@ -72,22 +72,23 @@ export namespace DEFAULT_STATE { export const dataFetchProgress: number; export const variables: {}; export namespace product { - export const productCode: null; - export const productName: null; - export const productDescription: null; - export const productSensor: null; - export const dateRange: null[]; - export const continuousDateRange: never[]; - export const sites: {}; + const productCode: null; + const productName: null; + const productDescription: null; + const productSensor: null; + const dateRange: null[]; + const continuousDateRange: never[]; + const sites: {}; } + export const release: null; export namespace graphData { - export const data: never[]; - export const qualityData: never[]; - export const monthOffsets: {}; - export const timestampMap: {}; - export const series: never[]; - export const labels: string[]; - export const qualityLabels: string[]; + const data: never[]; + const qualityData: never[]; + const monthOffsets: {}; + const timestampMap: {}; + const series: never[]; + const labels: string[]; + const qualityLabels: string[]; } export namespace selection { const dateRange_1: null[]; @@ -105,8 +106,8 @@ export namespace DEFAULT_STATE { export const rollPeriod: number; export const logscale: boolean; export namespace yAxes { - export const y1: any; - export const y2: any; + const y1: any; + const y2: any; } export const isDefault: boolean; export const invalidDefaultVariables: Set; @@ -199,6 +200,7 @@ export function getTestableItems(): { continuousDateRange: never[]; sites: {}; }; + release: null; graphData: { data: never[]; qualityData: never[]; @@ -272,8 +274,8 @@ export type ParseSiteVariablesReturn = { }; import PropTypes from "prop-types"; declare namespace VIEWER_MODE { - export const DEFAULT: string; - export const STATIC: string; + const DEFAULT: string; + const STATIC: string; } declare namespace FETCH_STATUS { export const AWAITING_CALL: string; @@ -292,22 +294,26 @@ declare namespace TimeSeriesViewerContext { */ declare function Provider(props: any): JSX.Element; declare namespace Provider { - export namespace propTypes { + namespace propTypes { const mode_1: PropTypes.Requireable; export { mode_1 as mode }; - import productCode_1 = productCode; + import productCode_1 = TimeSeriesViewerPropTypes.productCode; export { productCode_1 as productCode }; - import productData = productData; + import productData = TimeSeriesViewerPropTypes.productData; export { productData }; + const release_1: PropTypes.Requireable; + export { release_1 as release }; export const children: PropTypes.Validator; } - export namespace defaultProps { - import mode_2 = DEFAULT; + namespace defaultProps { + import mode_2 = VIEWER_MODE.DEFAULT; export { mode_2 as mode }; const productCode_2: null; export { productCode_2 as productCode }; const productData_1: null; export { productData_1 as productData }; + const release_2: null; + export { release_2 as release }; } } declare function useTimeSeriesViewerState(): any; diff --git a/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.js b/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.js index 25a46f01..374df790 100644 --- a/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.js +++ b/lib/components/TimeSeriesViewer/TimeSeriesViewerContext.js @@ -219,6 +219,7 @@ var DEFAULT_STATE = { continuousDateRange: [], sites: {} }, + release: null, graphData: { data: [], qualityData: [], @@ -1499,6 +1500,7 @@ var Provider = function Provider(props) { var modeProp = props.mode, productCodeProp = props.productCode, productDataProp = props.productData, + releaseProp = props.release, children = props.children; /** Initial State and Reducer Setup @@ -1519,6 +1521,7 @@ var Provider = function Provider(props) { initialState.product.productCode = productCodeProp; } + initialState.release = releaseProp; initialState.selection = applyDefaultsToSelection(initialState); var _useReducer = (0, _react.useReducer)(reducer, initialState), @@ -1565,7 +1568,7 @@ var Provider = function Provider(props) { type: 'initFetchProductCalled' }); - _NeonGraphQL.default.getDataProductByCode(state.product.productCode).pipe((0, _operators.map)(function (response) { + _NeonGraphQL.default.getDataProductByCode(state.product.productCode, state.release).pipe((0, _operators.map)(function (response) { if (response.response && response.response.data && response.response.data.product) { dispatch({ type: 'initFetchProductSucceeded', @@ -1586,7 +1589,7 @@ var Provider = function Provider(props) { }); return (0, _rxjs.of)(false); })).subscribe(); - }, [state.mode, state.status, state.fetchProduct.status, state.product.productCode]); + }, [state.mode, state.status, state.fetchProduct.status, state.product.productCode, state.release]); /** Effect - Handle changes to selection Triggers all necessary fetches for meta data and series data @@ -1596,7 +1599,9 @@ var Provider = function Provider(props) { var getSiteMonthDataURL = function getSiteMonthDataURL(siteCode, month) { var root = _NeonEnvironment.default.getFullApiPath('data'); - return "".concat(root, "/").concat(state.product.productCode, "/").concat(siteCode, "/").concat(month); + var hasRelease = state.release && typeof state.release === 'string' && state.release.length > 0; + var releaseParam = hasRelease ? "?release=".concat(state.release) : ''; + return "".concat(root, "/").concat(state.product.productCode, "/").concat(siteCode, "/").concat(month).concat(releaseParam); }; var _state$selection = state.selection, @@ -1844,7 +1849,7 @@ var Provider = function Provider(props) { }); } } - }, [state.mode, state.status, state.selection, state.selection.digest, state.variables, state.product]); + }, [state.mode, state.status, state.selection, state.selection.digest, state.variables, state.product, state.release]); /** Render */ @@ -1904,12 +1909,14 @@ Provider.propTypes = { mode: _propTypes.default.string, productCode: TimeSeriesViewerPropTypes.productCode, productData: TimeSeriesViewerPropTypes.productData, + release: _propTypes.default.string, children: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.string])), _propTypes.default.node, _propTypes.default.string]).isRequired }; Provider.defaultProps = { mode: VIEWER_MODE.DEFAULT, productCode: null, - productData: null + productData: null, + release: null }; /** Export diff --git a/lib/components/TimeSeriesViewer/TimeSeriesViewerDateRange.d.ts b/lib/components/TimeSeriesViewer/TimeSeriesViewerDateRange.d.ts index e36d98e5..821ef4b4 100644 --- a/lib/components/TimeSeriesViewer/TimeSeriesViewerDateRange.d.ts +++ b/lib/components/TimeSeriesViewer/TimeSeriesViewerDateRange.d.ts @@ -1,8 +1,8 @@ export default TimeSeriesViewerDateRange; declare function TimeSeriesViewerDateRange(props: any): JSX.Element; declare namespace TimeSeriesViewerDateRange { - export namespace propTypes { - export const dateRangeSliderRef: PropTypes.Validator; }>>; } diff --git a/lib/components/TimeSeriesViewer/TimeSeriesViewerSites.d.ts b/lib/components/TimeSeriesViewer/TimeSeriesViewerSites.d.ts index b907f408..e0bf5f3a 100644 --- a/lib/components/TimeSeriesViewer/TimeSeriesViewerSites.d.ts +++ b/lib/components/TimeSeriesViewer/TimeSeriesViewerSites.d.ts @@ -31,10 +31,10 @@ import { TabComponentPropTypes } from "./TimeSeriesViewerContext"; */ declare function PositionHistoryButton(props: any): JSX.Element; declare namespace PositionHistoryButton { - export namespace propTypes { - export const siteCode: PropTypes.Validator; - export const position: PropTypes.Validator; - export const history: PropTypes.Validator<(PropTypes.InferProps<{ + namespace propTypes { + const siteCode: PropTypes.Validator; + const position: PropTypes.Validator; + const history: PropTypes.Validator<(PropTypes.InferProps<{ 'HOR.VER': PropTypes.Validator; azimuth: PropTypes.Validator; pitch: PropTypes.Validator; @@ -95,9 +95,9 @@ declare namespace SelectedPosition { declare function SelectPositionsButton(props: any): JSX.Element; declare namespace SelectPositionsButton { export namespace propTypes_3 { - export const selectedSite: PropTypes.Validator; - positions: PropTypes.Validator[]>; + positions: PropTypes.Validator<(string | null | undefined)[]>; }>>; } export { propTypes_3 as propTypes }; @@ -125,11 +125,11 @@ declare namespace SelectedSite { const propTypes_4: { setSelectedTab: PropTypes.Validator<(...args: any[]) => any>; TAB_IDS: PropTypes.Validator<{ - [x: string]: import("../../types/core").Nullable; + [x: string]: string | null | undefined; }>; site: PropTypes.Validator; - positions: PropTypes.Validator[]>; + positions: PropTypes.Validator<(string | null | undefined)[]>; }>>; disabled: PropTypes.Requireable; }; @@ -142,14 +142,14 @@ declare namespace SelectedSite { } import PropTypes from "prop-types"; declare namespace ControlPropTypes { - export const children: PropTypes.Validator; - export const innerProps: PropTypes.Validator; + const innerProps: PropTypes.Validator any>; }>>; - export const innerRef: PropTypes.Validator<((...args: any[]) => any) | PropTypes.InferProps<{ + const innerRef: PropTypes.Validator<((...args: any[]) => any) | PropTypes.InferProps<{ current: PropTypes.Validator; }>>; - export const selectProps: PropTypes.Validator; + const selectProps: PropTypes.Validator; } declare namespace OptionPropTypes { const children_1: PropTypes.Requireable; diff --git a/lib/remoteAssets/drupal-header.html.d.ts b/lib/remoteAssets/drupal-header.html.d.ts index ec4993ea..1fe9e522 100644 --- a/lib/remoteAssets/drupal-header.html.d.ts +++ b/lib/remoteAssets/drupal-header.html.d.ts @@ -1,2 +1,2 @@ -declare var _default: "\n
\n
\n \n \n \n
\n Sign In\n
\n
\n
\n
\n \n \n \n\n\n \n\n
\n
\n \n
\n
\n

Search

\n \n\n
\n \n
\n \n\n \n
\n
\n\n\n
\n\n
\n\n\n\n\n
\n \n\n
\n
\n
\n
\n
\n\n\n"; +declare var _default: "\n
\n
\n \n \n \n
\n Sign In\n
\n
\n
\n
\n \n \n \n\n\n \n\n
\n
\n \n
\n
\n

Search

\n \n\n
\n \n
\n \n\n \n
\n
\n\n\n
\n\n
\n\n\n\n\n
\n \n\n
\n
\n
\n
\n
\n\n\n"; export default _default; diff --git a/lib/remoteAssets/drupal-header.html.js b/lib/remoteAssets/drupal-header.html.js index c26c47aa..1a113cc2 100644 --- a/lib/remoteAssets/drupal-header.html.js +++ b/lib/remoteAssets/drupal-header.html.js @@ -6,6 +6,6 @@ Object.defineProperty(exports, "__esModule", { exports.default = void 0; var html; -var _default = html = "\n
\n
\n \n \n \n
\n Sign In\n
\n
\n
\n
\n \n \n \n\n\n \n\n
\n
\n \n
\n
\n

Search

\n \n\n
\n \n
\n \n\n \n
\n
\n\n\n
\n\n
\n\n\n\n\n
\n \n\n
\n
\n
\n
\n
\n\n\n"; +var _default = html = "\n
\n
\n \n \n \n
\n Sign In\n
\n
\n
\n
\n \n \n \n\n\n \n\n
\n
\n \n
\n
\n

Search

\n \n\n
\n \n
\n \n\n \n
\n
\n\n\n
\n\n
\n\n\n\n\n
\n \n\n
\n
\n
\n
\n
\n\n\n"; exports.default = _default; \ No newline at end of file diff --git a/lib/remoteAssetsMap/package.json b/lib/remoteAssetsMap/package.json index 65fa0632..d4e43f84 100644 --- a/lib/remoteAssetsMap/package.json +++ b/lib/remoteAssetsMap/package.json @@ -1,4 +1,4 @@ { "type": "module", - "module": "./remoteAssetsMap.js" + "module": "./remoteAssets.js" } diff --git a/lib/remoteAssetsMap/remoteAssets.d.ts b/lib/remoteAssetsMap/remoteAssets.d.ts new file mode 100644 index 00000000..4c86b783 --- /dev/null +++ b/lib/remoteAssetsMap/remoteAssets.d.ts @@ -0,0 +1,16 @@ +export namespace REMOTE_ASSET_PATHS { + const DRUPAL_THEME_CSS: string; + const DRUPAL_HEADER_JS: string; + const DRUPAL_HEADER_HTML: string; + const DRUPAL_FOOTER_HTML: string; +} +export namespace REMOTE_ASSET_NAMES { + const DRUPAL_THEME_CSS_1: string; + export { DRUPAL_THEME_CSS_1 as DRUPAL_THEME_CSS }; + const DRUPAL_HEADER_JS_1: string; + export { DRUPAL_HEADER_JS_1 as DRUPAL_HEADER_JS }; + const DRUPAL_HEADER_HTML_1: string; + export { DRUPAL_HEADER_HTML_1 as DRUPAL_HEADER_HTML }; + const DRUPAL_FOOTER_HTML_1: string; + export { DRUPAL_FOOTER_HTML_1 as DRUPAL_FOOTER_HTML }; +} diff --git a/lib/remoteAssetsMap/remoteAssets.js b/lib/remoteAssetsMap/remoteAssets.js new file mode 100644 index 00000000..4f72cf8e --- /dev/null +++ b/lib/remoteAssetsMap/remoteAssets.js @@ -0,0 +1,20 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.REMOTE_ASSET_NAMES = exports.REMOTE_ASSET_PATHS = void 0; +var REMOTE_ASSET_PATHS = { + DRUPAL_THEME_CSS: '/themes/custom/neon/build/components/theme/theme.css', + DRUPAL_HEADER_JS: '/themes/custom/neon/build/components/header/header.js', + DRUPAL_HEADER_HTML: '/neon-assets/partial/header', + DRUPAL_FOOTER_HTML: '/neon-assets/partial/footer' +}; +exports.REMOTE_ASSET_PATHS = REMOTE_ASSET_PATHS; +var REMOTE_ASSET_NAMES = { + DRUPAL_THEME_CSS: 'drupal-theme.css', + DRUPAL_HEADER_JS: 'drupal-header.js', + DRUPAL_HEADER_HTML: 'drupal-header.html', + DRUPAL_FOOTER_HTML: 'drupal-footer.html' +}; +exports.REMOTE_ASSET_NAMES = REMOTE_ASSET_NAMES; \ No newline at end of file diff --git a/lib/remoteAssetsMap/remoteAssetsMap.d.ts b/lib/remoteAssetsMap/remoteAssetsMap.d.ts index c5d704c3..18920e46 100644 --- a/lib/remoteAssetsMap/remoteAssetsMap.d.ts +++ b/lib/remoteAssetsMap/remoteAssetsMap.d.ts @@ -1,22 +1,22 @@ export default REMOTE_ASSETS; declare namespace REMOTE_ASSETS { - export namespace DRUPAL_THEME_CSS { - export const name: string; - export const url: string; + namespace DRUPAL_THEME_CSS { + const name: string; + const url: string; } - export namespace DRUPAL_HEADER_JS { + namespace DRUPAL_HEADER_JS { const name_1: string; export { name_1 as name }; const url_1: string; export { url_1 as url }; } - export namespace DRUPAL_HEADER_HTML { + namespace DRUPAL_HEADER_HTML { const name_2: string; export { name_2 as name }; const url_2: string; export { url_2 as url }; } - export namespace DRUPAL_FOOTER_HTML { + namespace DRUPAL_FOOTER_HTML { const name_3: string; export { name_3 as name }; const url_3: string; diff --git a/lib/remoteAssetsMap/remoteAssetsMap.js b/lib/remoteAssetsMap/remoteAssetsMap.js index 3e073c99..3e4e8d8c 100644 --- a/lib/remoteAssetsMap/remoteAssetsMap.js +++ b/lib/remoteAssetsMap/remoteAssetsMap.js @@ -4,24 +4,31 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; + +var _NeonEnvironment = _interopRequireDefault(require("../components/NeonEnvironment/NeonEnvironment")); + +var _remoteAssets = require("./remoteAssets"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + // A structure containing local filenames and remote URLs for all remote assets used in // portal-core-components that we want to cache updated snapshots of at every lib build var REMOTE_ASSETS = { DRUPAL_THEME_CSS: { - name: 'drupal-theme.css', - url: 'https://www.neonscience.org/themes/custom/neon/build/components/theme/theme.css' + name: _remoteAssets.REMOTE_ASSET_NAMES.DRUPAL_THEME_CSS, + url: "".concat(_NeonEnvironment.default.getWebHost()).concat(_remoteAssets.REMOTE_ASSET_PATHS.DRUPAL_THEME_CSS) }, DRUPAL_HEADER_JS: { - name: 'drupal-header.js', - url: 'https://www.neonscience.org/themes/custom/neon/build/components/header/header.js' + name: _remoteAssets.REMOTE_ASSET_NAMES.DRUPAL_HEADER_JS, + url: "".concat(_NeonEnvironment.default.getWebHost()).concat(_remoteAssets.REMOTE_ASSET_PATHS.DRUPAL_HEADER_JS) }, DRUPAL_HEADER_HTML: { - name: 'drupal-header.html', - url: 'https://www.neonscience.org/neon-assets/partial/header' + name: _remoteAssets.REMOTE_ASSET_NAMES.DRUPAL_HEADER_HTML, + url: "".concat(_NeonEnvironment.default.getWebHost()).concat(_remoteAssets.REMOTE_ASSET_PATHS.DRUPAL_HEADER_HTML) }, DRUPAL_FOOTER_HTML: { - name: 'drupal-footer.html', - url: 'https://www.neonscience.org/neon-assets/partial/footer' + name: _remoteAssets.REMOTE_ASSET_NAMES.DRUPAL_FOOTER_HTML, + url: "".concat(_NeonEnvironment.default.getWebHost()).concat(_remoteAssets.REMOTE_ASSET_PATHS.DRUPAL_FOOTER_HTML) } }; // Replicate keys as attributes to allow for all variable references everywhere diff --git a/lib/service/DataCiteService.d.ts b/lib/service/DataCiteService.d.ts new file mode 100644 index 00000000..dead431a --- /dev/null +++ b/lib/service/DataCiteService.d.ts @@ -0,0 +1,26 @@ +export declare enum CitationDownloadType { + DATA_PRODUCT = "DATA_PRODUCT", + PROTOTYPE_DATASET = "PROTOTYPE_DATASET" +} +export interface CitationFormat { + shortName: string; + longName: string; + mime: string; + extension: string; + applicableDownloadtypes: CitationDownloadType[]; + generateProvisionalCitation: (product: Record) => string; + generateProtoDatasetProvisionalCitation: (dataset: Record) => string; +} +/** + * Service for working with DataCite + */ +export interface IDataCiteService { + getDoiUrl: (doi: string, format: CitationFormat) => string; + getCitationFormats: () => CitationFormat[]; + getDataProductFormats: () => CitationFormat[]; + getPrototypeDatasetFormats: () => CitationFormat[]; + downloadCitation: (formatShortName: string, type: CitationDownloadType, target: Record, doi: string, release?: string) => void; + executeDownload: (fileName: string, mimeType: string, payload: string) => void; +} +declare const DataCiteService: IDataCiteService; +export default DataCiteService; diff --git a/lib/service/DataCiteService.js b/lib/service/DataCiteService.js new file mode 100644 index 00000000..bb150ad5 --- /dev/null +++ b/lib/service/DataCiteService.js @@ -0,0 +1,173 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.CitationDownloadType = void 0; + +var _rxjs = require("rxjs"); + +var _operators = require("rxjs/operators"); + +var _ajax = require("rxjs/ajax"); + +var _NeonEnvironment = _interopRequireDefault(require("../components/NeonEnvironment/NeonEnvironment")); + +var _typeUtil = require("../util/typeUtil"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var CitationDownloadType; +exports.CitationDownloadType = CitationDownloadType; + +(function (CitationDownloadType) { + CitationDownloadType["DATA_PRODUCT"] = "DATA_PRODUCT"; + CitationDownloadType["PROTOTYPE_DATASET"] = "PROTOTYPE_DATASET"; +})(CitationDownloadType || (exports.CitationDownloadType = CitationDownloadType = {})); + +var DataCiteService = { + getDoiUrl: function getDoiUrl(doi, format) { + var mime = format.mime; + var doiId = (doi === null || doi === void 0 ? void 0 : doi.split('/').slice(-2).join('/')) || ''; + return "".concat(_NeonEnvironment.default.getDataCiteApiHost(), "/dois/").concat(mime, "/").concat(doiId); + }, + getCitationFormats: function getCitationFormats() { + return [{ + shortName: 'BibTex', + longName: 'BibTex', + mime: 'application/x-bibtex', + extension: 'bib', + applicableDownloadtypes: [CitationDownloadType.DATA_PRODUCT, CitationDownloadType.PROTOTYPE_DATASET], + generateProvisionalCitation: function generateProvisionalCitation(product) { + return "@misc{".concat(product.productCode, "/provisional,\n doi = {},\n url = {").concat(window.location.href, "},\n author = {{National Ecological Observatory Network (NEON)}},\n language = {en},\n title = {").concat(product.productName, " (").concat(product.productCode, ")},\n publisher = {National Ecological Observatory Network (NEON)},\n year = {").concat(new Date().getFullYear(), "}\n}"); + }, + generateProtoDatasetProvisionalCitation: function generateProtoDatasetProvisionalCitation(dataset) { + var id = "".concat(dataset.uuid, "/prototype"); + var doiId = ''; + var version = ''; + + if (dataset.doi && dataset.doi.url) { + id = dataset.doi.url; + doiId = id.split('/').slice(-2).join('/'); + } + + if (dataset.version) { + version = ", ".concat(dataset.version); + } + + return "@misc{".concat(id, ",\n doi = {").concat(doiId, "},\n url = {").concat(window.location.href, "},\n author = {National Ecological Observatory Network (NEON)},\n language = {en},\n title = {").concat(dataset.projectTitle).concat(version, " (").concat(dataset.uuid, ")},\n publisher = {National Ecological Observatory Network (NEON)},\n year = {").concat(new Date().getFullYear(), "}\n}"); + } + }, { + shortName: 'RIS', + longName: 'Research Information Systems (RIS)', + mime: 'application/x-research-info-systems', + extension: 'ris', + applicableDownloadtypes: [CitationDownloadType.DATA_PRODUCT, CitationDownloadType.PROTOTYPE_DATASET], + generateProvisionalCitation: function generateProvisionalCitation(product) { + return "TY - DATA\nT1 - ".concat(product.productName, " (").concat(product.productCode, ")\nAU - National Ecological Observatory Network (NEON)\nDO -\nUR - ").concat(window.location.href, "\nPY - ").concat(new Date().getFullYear(), "\nPB - National Ecological Observatory Network (NEON)\nLA - en\nER - "); + }, + generateProtoDatasetProvisionalCitation: function generateProtoDatasetProvisionalCitation(dataset) { + var doiId = ''; + var version = ''; + + if (dataset.doi && dataset.doi.url) { + doiId = dataset.doi.url.split('/').slice(-2).join('/'); + } + + if (dataset.version) { + version = ", ".concat(dataset.version); + } + + return "TY - DATA\nT1 - ".concat(dataset.projectTitle).concat(version, " (").concat(dataset.uuid, ")\nAU - National Ecological Observatory Network (NEON)\nDO - ").concat(doiId, "\nUR - ").concat(window.location.href, "\nAB - ").concat(dataset.datasetAbstract, "\nPY - ").concat(new Date().getFullYear(), "\nPB - National Ecological Observatory Network (NEON)\nLA - en\nER - "); + } + }]; + }, + getDataProductFormats: function getDataProductFormats() { + return DataCiteService.getCitationFormats().filter(function (value) { + return value.applicableDownloadtypes.includes(CitationDownloadType.DATA_PRODUCT); + }); + }, + getPrototypeDatasetFormats: function getPrototypeDatasetFormats() { + return DataCiteService.getCitationFormats().filter(function (value) { + return value.applicableDownloadtypes.includes(CitationDownloadType.PROTOTYPE_DATASET); + }); + }, + downloadCitation: function downloadCitation(formatShortName, type, target, doi, release) { + var useProvisional = release === 'provisional'; + var citationFormat = DataCiteService.getCitationFormats().find(function (value) { + return value.shortName.localeCompare(formatShortName) === 0; + }); + + if (!citationFormat) { + return; + } + + var fileName = ''; + var appliedRelease = (0, _typeUtil.isStringNonEmpty)(release) ? release : 'provisional'; + + switch (type) { + case CitationDownloadType.PROTOTYPE_DATASET: + fileName = "NEON-Prototype-Dataset-".concat(target.uuid, ".").concat(citationFormat.extension); + break; + + case CitationDownloadType.DATA_PRODUCT: + default: + fileName = "NEON-".concat(target.productCode, "-").concat(appliedRelease, ".").concat(citationFormat.extension); + break; + } + + if (useProvisional) { + var provCitation = ''; + + switch (type) { + case CitationDownloadType.PROTOTYPE_DATASET: + provCitation = citationFormat.generateProtoDatasetProvisionalCitation(target); + break; + + case CitationDownloadType.DATA_PRODUCT: + default: + provCitation = citationFormat.generateProvisionalCitation(target); + break; + } + + if (!(0, _typeUtil.isStringNonEmpty)(provCitation)) { + return; + } + + DataCiteService.executeDownload(fileName, citationFormat.mime, provCitation); + return; + } + + var citationUrl = DataCiteService.getDoiUrl(doi, citationFormat); + (0, _ajax.ajax)({ + url: citationUrl, + method: 'GET', + responseType: 'text' + }).pipe((0, _operators.map)(function (citationContent) { + DataCiteService.executeDownload(fileName, citationFormat.mime, citationContent.response); + }), (0, _operators.catchError)(function (error) { + // eslint-disable-next-line no-console + console.error("Unable to download citation ".concat(fileName), error); + return (0, _rxjs.of)(error); + })).subscribe(); + }, + executeDownload: function executeDownload(fileName, mimeType, payload) { + var link = document.createElement('a'); + + if (URL) { + link.href = URL.createObjectURL(new Blob([payload], { + type: mimeType + })); + } else { + link.setAttribute('href', "data:".concat(mimeType, ",").concat(encodeURI(payload))); + } + + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +}; +Object.freeze(DataCiteService); +var _default = DataCiteService; +exports.default = _default; \ No newline at end of file diff --git a/lib/service/RouteService.d.ts b/lib/service/RouteService.d.ts new file mode 100644 index 00000000..d0f024cf --- /dev/null +++ b/lib/service/RouteService.d.ts @@ -0,0 +1,149 @@ +/** + * Service for building routes and paths + */ +export interface IRouteService { + /** + * Gets the root web home page path + * @returns + */ + getWebHomePath: () => string; + /** + * Gets the path to the user accounts information page + * @returns + */ + getUserAccountsPath: () => string; + /** + * Gets the path to the NEON data policies information page + * @returns + */ + getDataPoliciesPath: () => string; + /** + * Gets the path to the NEON data citation policies information page + * @returns + */ + getDataPoliciesCitationPath: () => string; + /** + * Gets the path to the NEON data quality information page + * @returns + */ + getDataQualityPath: () => string; + /** + * Gets the path to the NEON news information page + * @returns + */ + getNewsPath: () => string; + /** + * Gets the path to the NEON data notifications information page + * @returns + */ + getDataNotificationsPath: () => string; + /** + * Gets the path to the NEON FAQ information page + * @returns + */ + getFaqPath: () => string; + /** + * Gets the path to the NEON download and explore information page + * @returns + */ + getDownloadExplorePath: () => string; + /** + * Gets the path to the NEON file naming conventions information page + * @returns + */ + getFileNamingConventionsPath: () => string; + /** + * Gets the path the NEON data revisions and releases information page + * @returns + */ + getDataRevisionsReleasePath: () => string; + /** + * Gets the data-samples path + * @returns + */ + getDataSamplesPath: () => string; + /** + * Gets the data-samples/data path + * @returns + */ + getDataSamplesDataPath: () => string; + /** + * Gets the samples path + * @returns + */ + getSamplesPath: () => string; + /** + * Gets the path to the data availability information page + * @returns + */ + getDataAvailabilityPath: () => string; + /** + * Gets the path to the NEONUtilities data stack in R page + * @returns + */ + getNeonUtilitiesDataStackRPath: () => string; + /** + * Gets the path to the theme detail page + * @param theme + * @returns + */ + getThemeDetailPath: (theme: string) => string; + /** + * Gets the path to the field site detail page + * @param siteCode + * @returns + */ + getFieldSiteDetailPath: (siteCode: string) => string; + /** + * Gets the path to the domain detail page + * @param domainCode + * @returns + */ + getDomainDetailPath: (domainCode: string) => string; + /** + * Gets the path to the release detail page + * @param release + * @returns + */ + getReleaseDetailPath: (release: string) => string; + /** + * Gets the data product citation download URL + * @returns + */ + getDataProductCitationDownloadUrl: () => string; + /** + * Gets the data api documentation path + * @returns + */ + getDataApiPath: () => string; + /** + * Gets the explore data products with with the query applied to search + * @returns + */ + getDataProductExploreSearchPath: (query: string) => string; + /** + * Gets the data product explore page path + * @returns + */ + getDataProductExplorePath: () => string; + /** + * Gets the product detail page path + * @param productCode The product code to build with + * @param release The release to build with + * @returns The full path to the page + */ + getProductDetailPath: (productCode: string, release?: string) => string; + /** + * Gets the prototype datasets page path + * @returns + */ + getPrototypeDatasetsPath: () => string; + /** + * Gets the prototype dataset detail page path + * @param uuid + * @returns + */ + getPrototypeDatasetDetailPath: (uuid: string) => string; +} +declare const RouteService: IRouteService; +export default RouteService; diff --git a/lib/service/RouteService.js b/lib/service/RouteService.js new file mode 100644 index 00000000..ecf5dc37 --- /dev/null +++ b/lib/service/RouteService.js @@ -0,0 +1,111 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _NeonEnvironment = _interopRequireDefault(require("../components/NeonEnvironment/NeonEnvironment")); + +var _typeUtil = require("../util/typeUtil"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var RouteService = { + getWebHomePath: function getWebHomePath() { + return _NeonEnvironment.default.getWebHost(); + }, + getUserAccountsPath: function getUserAccountsPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/about/user-accounts"); + }, + getDataPoliciesPath: function getDataPoliciesPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data/about-data/data-policies"); + }, + getDataPoliciesCitationPath: function getDataPoliciesCitationPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-policies-citation"); + }, + getDataQualityPath: function getDataQualityPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-management/data-quality-program"); + }, + getNewsPath: function getNewsPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/impact/newsroom/neon-news"); + }, + getDataNotificationsPath: function getDataNotificationsPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-notifications"); + }, + getFaqPath: function getFaqPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/about/faq"); + }, + getDownloadExplorePath: function getDownloadExplorePath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/resources/learning-hub/tutorials/download-explore-neon-data"); + }, + getFileNamingConventionsPath: function getFileNamingConventionsPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-management/data-formats-conventions"); + }, + getDataRevisionsReleasePath: function getDataRevisionsReleasePath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-management/data-revisions-releases"); + }, + getDataSamplesPath: function getDataSamplesPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples"); + }, + getSamplesPath: function getSamplesPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/samples"); + }, + getDataSamplesDataPath: function getDataSamplesDataPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data"); + }, + getDataAvailabilityPath: function getDataAvailabilityPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-management/data-availability"); + }, + getNeonUtilitiesDataStackRPath: function getNeonUtilitiesDataStackRPath() { + return "".concat(_NeonEnvironment.default.getWebHost(), "/resources/learning-hub/tutorials/neondatastackr"); + }, + getThemeDetailPath: function getThemeDetailPath(theme) { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data/data-themes/").concat(theme); + }, + getFieldSiteDetailPath: function getFieldSiteDetailPath(siteCode) { + return "".concat(_NeonEnvironment.default.getWebHost(), "/field-sites/").concat(siteCode); + }, + getDomainDetailPath: function getDomainDetailPath(domainCode) { + return "".concat(_NeonEnvironment.default.getWebHost(), "/domains/").concat(domainCode); + }, + getReleaseDetailPath: function getReleaseDetailPath(release) { + return "".concat(_NeonEnvironment.default.getWebHost(), "/data-samples/data-management/data-revisions-releases/").concat(release); + }, + getDataProductCitationDownloadUrl: function getDataProductCitationDownloadUrl() { + return (// TODO: replace with web host once switch over happens + _NeonEnvironment.default.getApiHost() + ); + }, + getDataApiPath: function getDataApiPath() { + return (// TODO: replace with web host once switch over happens + "".concat(_NeonEnvironment.default.getApiHost(), "/data-api") + ); + }, + getDataProductExploreSearchPath: function getDataProductExploreSearchPath(query) { + return "".concat(RouteService.getDataProductExplorePath(), "?search=").concat(encodeURIComponent(query)); + }, + getDataProductExplorePath: function getDataProductExplorePath() { + return (// TODO: replace with web host once switch over happens + "".concat(_NeonEnvironment.default.getApiHost(), "/data-products/explore") + ); + }, + getProductDetailPath: function getProductDetailPath(productCode, release) { + var releasePath = (0, _typeUtil.isStringNonEmpty)(release) ? "/".concat(release) : ''; // TODO: replace with web host once switch over happens + + return "".concat(_NeonEnvironment.default.getApiHost(), "/data-products/").concat(productCode).concat(releasePath); + }, + getPrototypeDatasetsPath: function getPrototypeDatasetsPath() { + return (// TODO: replace with web host once switch over happens + "".concat(_NeonEnvironment.default.getApiHost(), "/prototype-datasets") + ); + }, + getPrototypeDatasetDetailPath: function getPrototypeDatasetDetailPath(uuid) { + return (// TODO: replace with web host once switch over happens + "".concat(_NeonEnvironment.default.getApiHost(), "/prototype-datasets/").concat(uuid) + ); + } +}; +Object.freeze(RouteService); +var _default = RouteService; +exports.default = _default; \ No newline at end of file diff --git a/lib/util/liferayNotificationsUtil.js b/lib/util/liferayNotificationsUtil.js index 11ffdf14..da87fdd7 100644 --- a/lib/util/liferayNotificationsUtil.js +++ b/lib/util/liferayNotificationsUtil.js @@ -5,18 +5,16 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = exports.generateNotificationId = exports.getLiferayNotificationsApiPath = void 0; +var _NeonEnvironment = _interopRequireDefault(require("../components/NeonEnvironment")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + // NOTE: This is not defined in NeonEnvironment, where one would expect such // things, because this whole component is temporary. When Liferay is dead and // React pages can pull notifications from its replacement (Drupal), then this // should be appropriately refactored and hardened. var getLiferayNotificationsApiPath = function getLiferayNotificationsApiPath() { - var base = window.location.origin; // Override localhost dev - - if (base.includes('localhost')) { - base = 'https://local-data.neonscience.org'; - } - - return "".concat(base, "/auth0/liferaynotifications"); + return _NeonEnvironment.default.getFullAuthPath('notifications'); }; // Non-secure string hashing function found here: https://stackoverflow.com/a/8831937 // Use for unique id for notifications for keying nodes and tracking dismissal cookies diff --git a/lib/util/manifestUtil.js b/lib/util/manifestUtil.js index 4106cd78..900b0ecb 100644 --- a/lib/util/manifestUtil.js +++ b/lib/util/manifestUtil.js @@ -72,7 +72,8 @@ var buildManifestRequestUrl = function buildManifestRequestUrl(config) { dateRange = config.dateRange, packageType = config.packageType, documentation = config.documentation; - var url = "".concat(_NeonEnvironment.default.getFullApiPath('manifest'), "/manifest/rollup"); + + var url = _NeonEnvironment.default.getFullDownloadApiPath('manifestRollup'); if (!useBody) { var siteCodesParam = buildSiteCodesParams(sites); @@ -120,7 +121,7 @@ exports.buildS3FilesRequestUrl = buildS3FilesRequestUrl; var downloadManifest = function downloadManifest(manifest) { var form = document.createElement('form'); form.style.display = 'none'; - form.action = "".concat(_NeonEnvironment.default.getFullApiPath('download'), "/stream"); + form.action = _NeonEnvironment.default.getFullDownloadApiPath('downloadStream'); form.method = 'POST'; var input = document.createElement('input'); input.name = 'manifest'; diff --git a/package-lock.json b/package-lock.json index 82bf33ec..b9095560 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "portal-core-components", - "version": "1.7.2", + "version": "1.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.7.0", + "version": "1.8.0", "dependencies": { "@date-io/moment": "^1.3.9", "@material-ui/core": "^4.11.3", @@ -79,7 +79,7 @@ "react-scripts": "^4.0.3", "react-test-renderer": "^16.13.1", "serve": "^11.3.2", - "typescript": "^3.7.5", + "typescript": "^4.3.5", "worker-loader": "^3.0.0" } }, @@ -23905,9 +23905,9 @@ "integrity": "sha512-xlEvjfaTvFnr3ZmwM6fs5/KOKLpAuNksAUxiYfa6dKqZham2oTGm0gI1j/tcgxh1reihhrKbTFfFjtCV9wwxXA==" }, "node_modules/typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -28356,6 +28356,7 @@ "integrity": "sha512-hS4pxwn1ZGXVkmgD4tpFpaumUaAg2ZzbTrxltfC5yPw4BJV+mGkfnQOB4VpWEYZw2jv65Z0wLwDE/piQiPPZ3w==", "requires": { "@babel/runtime": "^7.6.0", + "@date-io/core": "1.x", "@types/styled-jsx": "^2.2.8", "clsx": "^1.0.2", "react-transition-group": "^4.0.0", @@ -44823,9 +44824,9 @@ "integrity": "sha512-xlEvjfaTvFnr3ZmwM6fs5/KOKLpAuNksAUxiYfa6dKqZham2oTGm0gI1j/tcgxh1reihhrKbTFfFjtCV9wwxXA==" }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "dev": true }, "unbox-primitive": { diff --git a/package.json b/package.json index d146b26b..84dc48b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "portal-core-components", - "version": "1.7.2", + "version": "1.8.0", "main": "./lib/index.js", "private": true, "homepage": "http://localhost:3010/core-components", @@ -77,22 +77,22 @@ "react-scripts": "^4.0.3", "react-test-renderer": "^16.13.1", "serve": "^11.3.2", - "typescript": "^3.7.5", + "typescript": "^4.3.5", "worker-loader": "^3.0.0" }, "scripts": { "start": "react-scripts start", - "start:prod": "mv build core-components && mkdir build && mv core-components/ build/ && node_modules/serve/bin/serve.js build", + "start:prod": "mv build core-components && mkdir build && mv core-components/ build/ && npx serve build", "build": "react-scripts build", - "test": "node node_modules/jest/bin/jest.js --config jest.config.js", - "test:updateSnapshots": "node node_modules/jest/bin/jest.js --config jest.config.js --updateSnapshot", - "lint": "(node_modules/eslint/bin/eslint.js src/ --ext .js,.jsx || true) && exit 0", - "lint:fix": "(node_modules/eslint/bin/eslint.js --fix src/ --ext .js,.jsx,.ts,.tsx || true) && exit 0", + "test": "npx jest --config jest.config.js", + "test:updateSnapshots": "npx jest --config jest.config.js --updateSnapshot", + "lint": "(npx eslint src/ --ext .js,.jsx || true) && exit 0", + "lint:fix": "(npx eslint --fix src/ --ext .js,.jsx,.ts,.tsx || true) && exit 0", "lib": "npm run lib:pre-process && npm run lib:babel-build && npm run lib:types && npm run lib:post-cleanup", "lib:babel-build": "NODE_ENV=production && babel ./src/lib_components --out-dir lib --extensions \".js,.jsx,.ts,.tsx\" --copy-files --no-copy-ignored", "lib:clean": "(rm -r ./lib || true) && (rm -r ./src/lib_components/remoteAssets/* || true)", "lib:clean-build": "npm run lib:clean && npm run lib", - "lib:types": "tsc --project tsconfig.d.json", + "lib:types": "npx tsc --project tsconfig.d.json", "lib:pre-process": "node ./scripts/lib/lib-cache-remote-assets.js", "lib:post-cleanup": "rm ./lib/components/**/StyleGuide.* && rm -rf ./lib/components/SiteMap/png && rm -rf ./lib/*/__tests__ && rm -rf ./lib/*/*/__tests__ && node ./scripts/lib/lib-fix-worker-babel.js" }, diff --git a/public/index.html b/public/index.html index c3dc2eb0..e6ba2123 100644 --- a/public/index.html +++ b/public/index.html @@ -1,37 +1,44 @@ - - NEON | Portal Core Components - - - - - - - - - - - - - - - - - - - -
- + + + NEON | Portal Core Components + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/scripts/lib/lib-cache-remote-assets.js b/scripts/lib/lib-cache-remote-assets.js index 85cad98f..cbb95574 100644 --- a/scripts/lib/lib-cache-remote-assets.js +++ b/scripts/lib/lib-cache-remote-assets.js @@ -14,12 +14,34 @@ import fetch from 'node-fetch'; import path, { dirname } from 'path'; import { fileURLToPath } from 'url'; -import REMOTE_ASSETS from '../../src/lib_components/remoteAssetsMap/remoteAssetsMap.js' +import { REMOTE_ASSET_PATHS, REMOTE_ASSET_NAMES } from '../../src/lib_components/remoteAssetsMap/remoteAssets.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); const CACHED_REMOTE_ASSETS_PATH = path.join(__dirname, '../../src/lib_components/remoteAssets'); +// When fetching cached remote assets, reference production +const REMOTE_ASSETS_CACHE = { + DRUPAL_THEME_CSS: { + name: REMOTE_ASSET_NAMES.DRUPAL_THEME_CSS, + url: `https://www.neonscience.org${REMOTE_ASSET_PATHS.DRUPAL_THEME_CSS}`, + }, + DRUPAL_HEADER_JS: { + name: REMOTE_ASSET_NAMES.DRUPAL_HEADER_JS, + url: `https://www.neonscience.org${REMOTE_ASSET_PATHS.DRUPAL_HEADER_JS}`, + }, + DRUPAL_HEADER_HTML: { + name: REMOTE_ASSET_NAMES.DRUPAL_HEADER_HTML, + url: `https://www.neonscience.org${REMOTE_ASSET_PATHS.DRUPAL_HEADER_HTML}`, + }, + DRUPAL_FOOTER_HTML: { + name: REMOTE_ASSET_NAMES.DRUPAL_FOOTER_HTML, + url: `https://www.neonscience.org${REMOTE_ASSET_PATHS.DRUPAL_FOOTER_HTML}`, + }, +}; + +Object.keys(REMOTE_ASSETS_CACHE).forEach((key) => { REMOTE_ASSETS_CACHE[key].KEY = key; }); + console.log('Caching remote assets...\n'); const fetches = []; @@ -27,7 +49,7 @@ const fetches = []; const sanitizeContent = (key, content) => { switch (key) { // DRUPAL_THEME_CSS - comment out all styles with relative path URLs (these will always fail) - case REMOTE_ASSETS.DRUPAL_THEME_CSS.KEY: + case REMOTE_ASSETS_CACHE.DRUPAL_THEME_CSS.KEY: content.match(/^(.*url\([\"\']((?!data)).*)$/mg).forEach((match) => { const replacement = match.endsWith('}') ? `/* ${match.slice(0, -1)} */ }` @@ -37,8 +59,8 @@ const sanitizeContent = (key, content) => { return content; // HTML files - convert to JS module that exports a string of the HTML content // We do this so that apps consuming portal-core-components don't need to configure html-loader - case REMOTE_ASSETS.DRUPAL_HEADER_HTML.KEY: - case REMOTE_ASSETS.DRUPAL_FOOTER_HTML.KEY: + case REMOTE_ASSETS_CACHE.DRUPAL_HEADER_HTML.KEY: + case REMOTE_ASSETS_CACHE.DRUPAL_FOOTER_HTML.KEY: content = content.replace(/`/g, '\\`'); return `let html;\nexport default html = \`${content}\`;`; default: @@ -46,10 +68,10 @@ const sanitizeContent = (key, content) => { } }; -Object.keys(REMOTE_ASSETS) +Object.keys(REMOTE_ASSETS_CACHE) .filter((key) => key !== 'default') .forEach((key) => { - const { name, url } = REMOTE_ASSETS[key]; + const { name, url } = REMOTE_ASSETS_CACHE[key]; console.log(`* Fetching: ${name}`); const promise = fetch(url) .then((res) => { diff --git a/src/components/Home.jsx b/src/components/Home.jsx index 354d4fc8..5d9baa74 100644 --- a/src/components/Home.jsx +++ b/src/components/Home.jsx @@ -8,6 +8,7 @@ import Typography from '@material-ui/core/Typography'; import DocBlock from './DocBlock'; +import NeonEnvironment from '../lib_components/components/NeonEnvironment/NeonEnvironment'; import Theme from '../lib_components/components/Theme/Theme'; const useStyles = makeStyles((theme) => ({ @@ -25,7 +26,7 @@ export default function Home() { NEON Data Portal Core Components is an open source library of React components - intended for use on NEON Data Portal pages. + intended for use on NEON Data Portal pages. This page and component pages accessed through the navigation links provided here serves diff --git a/src/lib_components/components/DownloadDataContext/DownloadDataContext.jsx b/src/lib_components/components/DownloadDataContext/DownloadDataContext.jsx index 8339ecd8..2f0769dc 100644 --- a/src/lib_components/components/DownloadDataContext/DownloadDataContext.jsx +++ b/src/lib_components/components/DownloadDataContext/DownloadDataContext.jsx @@ -222,7 +222,7 @@ const newStateIsAllowable = (key, value) => { case 'sites': return ( Array.isArray(value) - && value.every((site) => (typeof site === 'string' && /^[A-Z]{4}$/.test(site))) + && value.every((site) => (typeof site === 'string' && /^[A-Z]{4}$/.test(site))) ); case 'dateRange': return ( @@ -290,7 +290,7 @@ const newStateIsValid = (key, value, validValues = []) => { default: return ( newStateIsAllowable(key, value) - && (!Array.isArray(validValues) || validValues.includes(value)) + && (!Array.isArray(validValues) || validValues.includes(value)) ); } }; @@ -580,7 +580,7 @@ const getAndValidateNewS3FilesState = (previousState, action, broadcast = false) newState.s3Files.estimatedPostSize = estimatePostSize(newState.s3Files, newState.sites); newState.s3Files.isValid = ( newState.s3Files.value.length > 0 - && newState.s3Files.estimatedPostSize < MAX_POST_BODY_SIZE + && newState.s3Files.estimatedPostSize < MAX_POST_BODY_SIZE ); if (s3FilesIdx !== -1) { newState.requiredSteps[s3FilesIdx].isComplete = newState.s3Files.isValid; @@ -704,8 +704,8 @@ const getAndValidateNewState = (previousState, action, broadcast = false) => { // Trigger a new manifest request for file size estimate if this update warrants it if ( previousState.fromManifest - && MANIFEST_TRIGGERING_STATE_KEYS.includes(action.key) - && broadcast + && MANIFEST_TRIGGERING_STATE_KEYS.includes(action.key) + && broadcast ) { newState.manifest.status = 'awaitingFetchCall'; } @@ -957,7 +957,7 @@ const useDownloadDataState = () => { requiredSteps: [], downloadContextIsActive: false, }, - () => {}, + () => { }, ]; } return hookResponse; diff --git a/src/lib_components/components/DownloadDataDialog/DownloadDataDialog.jsx b/src/lib_components/components/DownloadDataDialog/DownloadDataDialog.jsx index 6d03fe0b..7d8f0b95 100644 --- a/src/lib_components/components/DownloadDataDialog/DownloadDataDialog.jsx +++ b/src/lib_components/components/DownloadDataDialog/DownloadDataDialog.jsx @@ -40,6 +40,7 @@ import NeonContext from '../NeonContext/NeonContext'; import NeonEnvironment from '../NeonEnvironment/NeonEnvironment'; import Theme, { COLORS } from '../Theme/Theme'; +import RouteService from '../../service/RouteService'; import { buildManifestConfig, buildManifestRequestBody, @@ -318,21 +319,6 @@ export default function DownloadDataDialog() { const bytes = getSizeEstimateBytes(); if (bytes < DOWNLOAD_SIZE_WARN) { return null; } const formattedBytes = formatBytes(bytes); - const aopHardDriveLink = ( - - AOP Data to Hard Drive Request - - ); - const aopBlurb = ( - <> - {/* eslint-disable react/jsx-one-expression-per-line */} - An alternate way to obtain lots of AOP data is to submit an {aopHardDriveLink}. - {/* eslint-enable react/jsx-one-expression-per-line */} - - ); return ( @@ -345,7 +331,7 @@ export default function DownloadDataDialog() { If needed, you can reduce the download size by selecting fewer sites - or a more restrictive date range. {fromAOPManifest ? aopBlurb : null} + or a more restrictive date range. {/* eslint-enable react/jsx-one-expression-per-line */} @@ -428,7 +414,7 @@ export default function DownloadDataDialog() { signing in ); const benefitsLink = ( - here + here ); /* eslint-disable react/jsx-one-expression-per-line */ const authStyles = { color: COLORS.GOLD[800], textAlign: 'right', whiteSpace: 'nowrap' }; diff --git a/src/lib_components/components/DownloadStepForm/DownloadStepForm.jsx b/src/lib_components/components/DownloadStepForm/DownloadStepForm.jsx index 0344762a..e551699f 100644 --- a/src/lib_components/components/DownloadStepForm/DownloadStepForm.jsx +++ b/src/lib_components/components/DownloadStepForm/DownloadStepForm.jsx @@ -48,6 +48,7 @@ import MaterialTableIcons from '../MaterialTableIcons/MaterialTableIcons'; import SiteChip from '../SiteChip/SiteChip'; import Theme, { COLORS } from '../Theme/Theme'; +import RouteService from '../../service/RouteService'; import { formatBytes, MAX_POST_BODY_SIZE } from '../../util/manifestUtil'; const useStyles = makeStyles((theme) => ({ @@ -147,7 +148,7 @@ const useStyles = makeStyles((theme) => ({ const dataUsageAndCitationPoliciesLink = ( Data Usage and Citation Policies @@ -236,7 +237,7 @@ export default function DownloadStepForm(props) { const neonFaqLink = ( NEON FAQ @@ -733,7 +734,7 @@ export default function DownloadStepForm(props) { const downloadAndExploreLink = ( Download and Explore NEON Data @@ -759,7 +760,7 @@ export default function DownloadStepForm(props) { const fileNamingConventionsLink = ( NEON File Naming Conventions @@ -784,7 +785,7 @@ export default function DownloadStepForm(props) { const year = moment().format('YYYY'); const today = moment().format('MMMM D, YYYY'); const maturity = 'Provisional'; - const url = 'http://data.neonscience.org'; + const url = RouteService.getDataProductCitationDownloadUrl(); const citationText = `National Ecological Observatory Network. ${year}. Data Product ${productCode}, ${productName}. ${maturity} data downloaded from ${url} on ${today}. Battelle, Boulder, CO, USA NEON. ${year}.`; const citationCallout = ( - National Ecological Observatory Network. 2019. Data Product undefined, undefined. Provisional data downloaded from http://data.neonscience.org on December 31, 2019. Battelle, Boulder, CO, USA NEON. 2019. + National Ecological Observatory Network. 2019. Data Product undefined, undefined. Provisional data downloaded from https://data.neonscience.org on December 31, 2019. Battelle, Boulder, CO, USA NEON. 2019.

diff --git a/src/lib_components/components/NeonApi/NeonApi.js b/src/lib_components/components/NeonApi/NeonApi.js index 042e135a..ad46919c 100644 --- a/src/lib_components/components/NeonApi/NeonApi.js +++ b/src/lib_components/components/NeonApi/NeonApi.js @@ -150,7 +150,7 @@ const NeonApi = { ), getPrototypeManifestRollupObservable: (uuid) => ( // eslint-disable-next-line max-len - getJsonObservable(`${NeonEnvironment.getFullApiPath('manifest')}/prototype/manifest/rollup?uuid=${uuid}`) + getJsonObservable(`${NeonEnvironment.getFullDownloadApiPath('prototypeManifestRollup')}?uuid=${uuid}`) ), getPrototypeDataFileObservable: (uuid, fileName) => ( getJsonObservable(`${NeonEnvironment.getFullApiPath('prototype')}/data/${uuid}/${fileName}`) diff --git a/src/lib_components/components/NeonAuth/AuthService.ts b/src/lib_components/components/NeonAuth/AuthService.ts index 78133dc8..9be9a347 100644 --- a/src/lib_components/components/NeonAuth/AuthService.ts +++ b/src/lib_components/components/NeonAuth/AuthService.ts @@ -13,7 +13,7 @@ import { Message, StompHeaders } from '@stomp/stompjs'; import { RxStomp, RxStompConfig, RxStompState } from '@stomp/rx-stomp'; import NeonApi from '../NeonApi'; -import NeonEnvironment from '../NeonEnvironment/NeonEnvironment'; +import NeonEnvironment, { INeonEnvironment } from '../NeonEnvironment/NeonEnvironment'; import BrowserService from '../../util/browserUtil'; import { getJson } from '../../util/rxUtil'; @@ -70,14 +70,24 @@ export interface IAuthService { /** * Initializes a login flow * @param {string} path - Optionally path to set for the root login URL + * @param {string} redirectUriPath - Optionally set the redirect path */ - login: (path?: string) => void; + login: (path?: string, redirectUriPath?: string) => void; /** * Performs a silent login flow * @param {Dispatch} dispatch - The NeonContext dispatch function * @param {boolean} isSsoCheck - Whether or not performaing an SSO check + * @param {string} path - Fallback to optionally path to set for the + * root logout URL when defaulting to normal login flow. + * @param {string} redirectUriPath - Fallback to optionally set the + * redirect path when defaulting to normal login flow. */ - loginSilently: (dispatch: Dispatch, isSsoCheck: boolean) => void; + loginSilently: ( + dispatch: Dispatch, + isSsoCheck: boolean, + path?: string, + redirectUriPath?: string, + ) => void; /** * Initializes a logout flow * @param {string} path - Optionally path to set for the root logout URL @@ -88,8 +98,16 @@ export interface IAuthService { * Performs a silent logout flow * @param {Dispatch} dispatch - The NeonContext dispatch function * upon logout + * @param {string} path - Fallback to optionally path to set for the + * root logout URL when defaulting to normal login flow. + * @param {string} redirectUriPath - Fallback to optionally set the + * redirect path when defaulting to normal login flow. */ - logoutSilently: (dispatch: Dispatch) => void; + logoutSilently: ( + dispatch: Dispatch, + path?: string, + redirectUriPath?: string, + ) => void; /** * Cancels the user info request */ @@ -272,16 +290,23 @@ const AuthService: IAuthService = { NeonEnvironment.route.account(), ].indexOf(NeonEnvironment.getRouterBaseHomePath() || '') >= 0 ), - login: (path?: string): void => { - const env: any = NeonEnvironment; + login: (path?: string, redirectUriPath?: string): void => { + const env: INeonEnvironment = NeonEnvironment; const rootPath: string = exists(path) - ? path + ? (path as string) : env.getFullAuthPath('login'); - const redirectUri = `${env.route.getFullRoute(env.getRouterBaseHomePath())}`; - const href = `${rootPath}?${REDIRECT_URI}=${redirectUri}`; + const appliedRedirectUri = exists(redirectUriPath) + ? redirectUriPath + : env.route.getFullRoute(env.getRouterBaseHomePath()); + const href = `${rootPath}?${REDIRECT_URI}=${appliedRedirectUri}`; window.location.href = href; }, - loginSilently: (dispatch: Dispatch, isSsoCheck: boolean): void => { + loginSilently: ( + dispatch: Dispatch, + isSsoCheck: boolean, + path?: string, + redirectUriPath?: string, + ): void => { // Until custom domains are implemented, // Safari does not support silent auth flow const allowSilent: boolean = AuthService.allowSilentAuth(); @@ -289,7 +314,7 @@ const AuthService: IAuthService = { return; } if (!allowSilent) { - AuthService.login(); + AuthService.login(path, redirectUriPath); return; } dispatch({ type: 'setAuthWorking', isAuthWorking: true }); @@ -321,22 +346,26 @@ const AuthService: IAuthService = { ); }, logout: (path?: string, redirectUriPath?: string): void => { - const env: any = NeonEnvironment; + const env: INeonEnvironment = NeonEnvironment; const rootPath: string = exists(path) - ? path + ? (path as string) : env.getFullAuthPath('logout'); const appliedRedirectUri = exists(redirectUriPath) - ? `${env.getHost()}${redirectUriPath}` - : `${env.getHost()}${env.route.getFullRoute(env.getRouterBaseHomePath())}`; + ? `${env.getApiHost()}${redirectUriPath}` + : `${env.getApiHost()}${env.route.getFullRoute(env.getRouterBaseHomePath())}`; const href = `${rootPath}?${REDIRECT_URI}=${appliedRedirectUri}`; window.location.href = href; }, - logoutSilently: (dispatch: Dispatch): void => { + logoutSilently: ( + dispatch: Dispatch, + path?: string, + redirectUriPath?: string, + ): void => { // Until custom domains are implemented, // Safari does not support silent auth flow const allowSilent: boolean = AuthService.allowSilentAuth(); if (!allowSilent) { - AuthService.logout(); + AuthService.logout(path, redirectUriPath); return; } dispatch({ type: 'setAuthWorking', isAuthWorking: true }); diff --git a/src/lib_components/components/NeonAuth/NeonAuth.tsx b/src/lib_components/components/NeonAuth/NeonAuth.tsx index 9a1d9082..ea85b965 100644 --- a/src/lib_components/components/NeonAuth/NeonAuth.tsx +++ b/src/lib_components/components/NeonAuth/NeonAuth.tsx @@ -13,6 +13,7 @@ import Theme from '../Theme/Theme'; import { StringPropsObject } from '../../types/objectTypes'; import { StylesHook } from '../../types/muiTypes'; import { Undef } from '../../types/core'; +import { isStringNonEmpty } from '../../util/typeUtil'; export enum NeonAuthType { REDIRECT = 'REDIRECT', @@ -60,7 +61,7 @@ const triggerAuth = ( setTimeout( () => { if (login) { - AuthService.login(path); + AuthService.login(path, redirectUriPath); } else { AuthService.logout(path, redirectUriPath); } @@ -92,13 +93,17 @@ const renderAuth = ( if (!isAuthWsConnected) { appliedLoginType = NeonAuthType.REDIRECT; } + const appHomePath: string = NeonEnvironment.getRouterBaseHomePath(); + const currentPath: string = window.location.pathname; + const hasPath: boolean = isStringNonEmpty(currentPath) && currentPath.includes(appHomePath); + const redirectUriPath: Undef = hasPath ? currentPath : undefined; switch (appliedLoginType) { case NeonAuthType.SILENT: - AuthService.loginSilently(dispatch, false); + AuthService.loginSilently(dispatch, false, loginPath, redirectUriPath); break; case NeonAuthType.REDIRECT: default: - triggerAuth(loginPath, true, dispatch); + triggerAuth(loginPath, true, dispatch, redirectUriPath); break; } }; @@ -109,14 +114,19 @@ const renderAuth = ( if (!isAuthWsConnected) { appliedLogoutType = NeonAuthType.REDIRECT; } - const appPath: string = NeonEnvironment.getRouterBaseHomePath() || ''; - if (LOGOUT_REDIRECT_PATHS.indexOf(appPath) >= 0) { + const appHomePath: string = NeonEnvironment.getRouterBaseHomePath(); + if (LOGOUT_REDIRECT_PATHS.indexOf(appHomePath) >= 0) { appliedLogoutType = NeonAuthType.REDIRECT; redirectUriPath = NeonEnvironment.route.home(); + } else { + // If not a auto redirect path, redirect back to the current path + const currentPath: string = window.location.pathname; + const hasPath: boolean = isStringNonEmpty(currentPath) && currentPath.includes(appHomePath); + redirectUriPath = hasPath ? currentPath : appHomePath; } switch (appliedLogoutType) { case NeonAuthType.SILENT: - AuthService.logoutSilently(dispatch); + AuthService.logoutSilently(dispatch, logoutPath, redirectUriPath); break; case NeonAuthType.REDIRECT: default: diff --git a/src/lib_components/components/NeonContext/NeonContext.jsx b/src/lib_components/components/NeonContext/NeonContext.jsx index 57281032..b566e49a 100644 --- a/src/lib_components/components/NeonContext/NeonContext.jsx +++ b/src/lib_components/components/NeonContext/NeonContext.jsx @@ -127,12 +127,16 @@ const reducer = (state, action) => { case 'fetchSitesSucceeded': newState.fetches.sites.status = FETCH_STATUS.SUCCESS; newState.data.sites = action.sites; - newState.isFinal = true; + newState.isFinal = !newState.auth.useCore + || ((newState.fetches.auth.status === FETCH_STATUS.SUCCESS) + || (newState.fetches.auth.status === FETCH_STATUS.ERROR)); return deriveRegionSites(newState); case 'fetchSitesFailed': newState.fetches.sites.status = FETCH_STATUS.ERROR; newState.fetches.sites.error = action.error; - newState.isFinal = true; + newState.isFinal = !newState.auth.useCore + || ((newState.fetches.auth.status === FETCH_STATUS.SUCCESS) + || (newState.fetches.auth.status === FETCH_STATUS.ERROR)); newState.hasError = true; return newState; @@ -150,12 +154,16 @@ const reducer = (state, action) => { newState.fetches.auth.status = FETCH_STATUS.SUCCESS; newState.auth.isAuthenticated = !!action.isAuthenticated; newState.auth.userData = AuthService.parseUserData(action.response); + newState.isFinal = (newState.fetches.sites.status === FETCH_STATUS.SUCCESS) + || (newState.fetches.sites.status === FETCH_STATUS.ERROR); return newState; case 'fetchAuthFailed': newState.fetches.auth.status = FETCH_STATUS.ERROR; newState.fetches.auth.error = action.error; newState.auth.isAuthenticated = false; newState.auth.userData = null; + newState.isFinal = (newState.fetches.sites.status === FETCH_STATUS.SUCCESS) + || (newState.fetches.sites.status === FETCH_STATUS.ERROR); return newState; // Actions for handling remote assets @@ -293,7 +301,7 @@ const Provider = (props) => { AuthService.loginSilently(dispatch, true); } } else { - AuthService.login(); + dispatch({ type: 'fetchAuthSucceeded', isAuthenticated, response }); } } else { dispatch({ type: 'fetchAuthSucceeded', isAuthenticated, response }); diff --git a/src/lib_components/components/NeonEnvironment/NeonEnvironment.js b/src/lib_components/components/NeonEnvironment/NeonEnvironment.js deleted file mode 100644 index 1a818235..00000000 --- a/src/lib_components/components/NeonEnvironment/NeonEnvironment.js +++ /dev/null @@ -1,288 +0,0 @@ -/* eslint-disable no-restricted-globals */ - -import { AuthSilentType } from '../../types/core'; - -// Names of all environment variables that MUST be explicitly defined for the -// environment to be reported as "valid". These are evnironment variables -// that are expected to be referenced by all apps. Standard vars present in all -// node environments (e.g. PORT, NODE_ENV, etc.) are not listed here. -export const requiredEnvironmentVars = [ - 'REACT_APP_NEON_API_NAME', - 'REACT_APP_NEON_API_VERSION', - 'REACT_APP_NEON_AUTH_API', - 'REACT_APP_NEON_AUTH_WS_API', - 'REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API', - 'REACT_APP_NEON_AUTH_LOGIN', - 'REACT_APP_NEON_AUTH_LOGOUT', - 'REACT_APP_NEON_AUTH_USERINFO', - 'REACT_APP_NEON_PATH_MENU_API', - 'REACT_APP_NEON_PATH_PUBLIC_GRAPHQL', - 'REACT_APP_NEON_ROUTER_BASE', - 'REACT_APP_NEON_ROUTER_BASE_HOME', - 'REACT_APP_NEON_USE_GRAPHQL', -]; - -// Names of additional environment variables that may be referenced by -// this module depending on a given app's use case. Along with the above -// required list this makes a complete set of all environment variables -// this module will ever reference. -export const optionalEnvironmentVars = [ - 'REACT_APP_NEON_PATH_LD_API', - 'REACT_APP_NEON_PATH_LD_REPO_API', - 'REACT_APP_NEON_PATH_AOP_DOWNLOAD_API', - 'REACT_APP_NEON_PATH_DATA_API', - 'REACT_APP_NEON_PATH_DOCUMENTS_API', - 'REACT_APP_NEON_PATH_DOWNLOAD_API', - 'REACT_APP_NEON_PATH_MANIFEST_API', - 'REACT_APP_NEON_PATH_PRODUCTS_API', - 'REACT_APP_NEON_PATH_PROTOTYPE_DATA_API', - 'REACT_APP_NEON_PATH_RELEASES_API', - 'REACT_APP_NEON_PATH_SITES_API', - 'REACT_APP_NEON_PATH_LOCATIONS_API', - 'REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS', - 'REACT_APP_NEON_SHOW_AOP_VIEWER', - 'REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL', - 'REACT_APP_NEON_VISUS_IFRAME_BASE_URL', - 'REACT_APP_NEON_HOST_OVERRIDE', - 'REACT_APP_NEON_WS_HOST_OVERRIDE', - 'REACT_APP_FOREIGN_LOCATION', - 'REACT_APP_NEON_AUTH_DISABLE_WS', - 'REACT_APP_NEON_ROUTER_NEON_HOME', - 'REACT_APP_NEON_ROUTER_NEON_MYACCOUNT', -]; - -// Temporary paths that shouldn't need to propogate to environment files until made more permanent -const REACT_APP_NEON_PATH_ARCGIS_ASSETS_API = '/arcgis-assets'; - -const EnvType = { - DEV: 'development', - PROD: 'production', -}; - -const NeonEnvironment = { - isValid: requiredEnvironmentVars.every((envVar) => typeof process.env[envVar] !== 'undefined'), - isDevEnv: process.env.NODE_ENV === EnvType.DEV, - isProdEnv: process.env.NODE_ENV === EnvType.PROD, - isForeignEnv: process.env.REACT_APP_FOREIGN_LOCATION === 'true', - useGraphql: process.env.REACT_APP_NEON_USE_GRAPHQL === 'true', - showAopViewer: process.env.REACT_APP_NEON_SHOW_AOP_VIEWER === 'true', - authDisableWs: process.env.REACT_APP_NEON_AUTH_DISABLE_WS === 'true', - - getApiName: () => process.env.REACT_APP_NEON_API_NAME, - getApiVersion: () => process.env.REACT_APP_NEON_API_VERSION, - getRootApiPath: () => `/${process.env.REACT_APP_NEON_API_NAME}/${process.env.REACT_APP_NEON_API_VERSION}`, - getRootGraphqlPath: () => process.env.REACT_APP_NEON_PATH_PUBLIC_GRAPHQL, - getRootJsonLdPath: () => `${NeonEnvironment.getRootApiPath()}${process.env.REACT_APP_NEON_PATH_LD_API}`, - getRootAuthApiPath: () => process.env.REACT_APP_NEON_AUTH_API, - - getApiPath: { - aopDownload: () => process.env.REACT_APP_NEON_PATH_AOP_DOWNLOAD_API, - data: () => process.env.REACT_APP_NEON_PATH_DATA_API, - prototype: () => process.env.REACT_APP_NEON_PATH_PROTOTYPE_DATA_API, - documents: () => process.env.REACT_APP_NEON_PATH_DOCUMENTS_API, - download: () => process.env.REACT_APP_NEON_PATH_DOWNLOAD_API, - manifest: () => process.env.REACT_APP_NEON_PATH_MANIFEST_API, - menu: () => process.env.REACT_APP_NEON_PATH_MENU_API, - products: () => process.env.REACT_APP_NEON_PATH_PRODUCTS_API, - releases: () => process.env.REACT_APP_NEON_PATH_RELEASES_API, - sites: () => process.env.REACT_APP_NEON_PATH_SITES_API, - locations: () => process.env.REACT_APP_NEON_PATH_LOCATIONS_API, - arcgisAssets: () => REACT_APP_NEON_PATH_ARCGIS_ASSETS_API, - }, - - getApiLdPath: { - repo: () => process.env.REACT_APP_NEON_PATH_LD_REPO_API, - }, - - getPagePath: { - fileNamingConventions: () => process.env.REACT_APP_NEON_PATH_FILE_NAMING_CONVENTIONS, - }, - - getAuthPath: { - login: () => process.env.REACT_APP_NEON_AUTH_LOGIN, - logout: () => process.env.REACT_APP_NEON_AUTH_LOGOUT, - userInfo: () => process.env.REACT_APP_NEON_AUTH_USERINFO, - seamlessLogin: () => `${NeonEnvironment.getAuthPath.login()}?seamless=true`, - silentLogin: () => `${NeonEnvironment.getAuthPath.login()}?silent=true`, - silentLogout: () => `${NeonEnvironment.getAuthPath.logout()}?silent=true`, - }, - getAuthApiPath: { - ws: () => process.env.REACT_APP_NEON_AUTH_WS_API, - }, - authTopics: { - getAuth0: () => process.env.REACT_APP_NEON_AUTH_WS_TOPIC_AUTH0_API, - }, - - getVisusProductsBaseUrl: () => process.env.REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL, - getVisusIframeBaseUrl: () => process.env.REACT_APP_NEON_VISUS_IFRAME_BASE_URL, - - getRouterBasePath: () => process.env.REACT_APP_NEON_ROUTER_BASE, - getRouterBaseHomePath: () => process.env.REACT_APP_NEON_ROUTER_BASE_HOME, - getHostOverride: () => process.env.REACT_APP_NEON_HOST_OVERRIDE, - getWsHostOverride: () => process.env.REACT_APP_NEON_WS_HOST_OVERRIDE, - - route: { - home: () => process.env.REACT_APP_NEON_ROUTER_NEON_HOME || '/home', - account: () => process.env.REACT_APP_NEON_ROUTER_NEON_MYACCOUNT || '/myaccount', - getFullRoute: (route = '') => `${NeonEnvironment.getRouterBasePath()}${route}`, - buildRouteFromHost: (route = '') => ( - `${NeonEnvironment.getHost()}${NeonEnvironment.route.getFullRoute(route)}` - ), - buildHomeRoute: () => ( - `${NeonEnvironment.getHost()}${NeonEnvironment.route.home()}` - ), - buildAccountRoute: () => ( - `${NeonEnvironment.getHost()}${NeonEnvironment.route.account()}` - ), - }, - - /** - * Gets the window.NEON_SERVER_DATA injected from the server environment. - * @return {Object} The structured server data object - */ - getNeonServerData: () => { - /* eslint-disable */ - if (typeof WorkerGlobalScope === 'function') { - return self.NEON_SERVER_DATA ? self.NEON_SERVER_DATA : null; - } - /* eslint-enable */ - if (typeof window === 'object') { - return window.NEON_SERVER_DATA ? window.NEON_SERVER_DATA : null; - } - return null; - }, - - getHost: () => { - if ( - (NeonEnvironment.isDevEnv || NeonEnvironment.isForeignEnv) - && NeonEnvironment.getHostOverride()) { - return NeonEnvironment.getHostOverride(); - } - /* eslint-disable */ - if (typeof WorkerGlobalScope === 'function' && typeof self.location === 'object') { - return `${self.location.protocol}//${self.location.host}`; - } - /* eslint-enable */ - return `${window.location.protocol}//${window.location.host}`; - }, - - getWebSocketHost: () => { - if ( - (NeonEnvironment.isDevEnv || NeonEnvironment.isForeignEnv) - && NeonEnvironment.getWsHostOverride()) { - return NeonEnvironment.getWsHostOverride(); - } - return window.location.protocol.startsWith('https') - ? `wss://${window.location.host}` - : `ws://${window.location.host}`; - }, - - /** - * Gets the API token header name - * @return {string} The API token header name - */ - getApiTokenHeader: () => { - const serverData = NeonEnvironment.getNeonServerData(); - if (serverData && (typeof serverData.NeonPublicAPITokenHeader === 'string')) { - return serverData.NeonPublicAPITokenHeader; - } - return ''; - }, - - /** - * Gets the API token value - * @return {string} The API token value - */ - getApiToken: () => { - const serverData = NeonEnvironment.getNeonServerData(); - if (serverData && (typeof serverData.NeonPublicAPIToken === 'string')) { - return serverData.NeonPublicAPIToken; - } - return ''; - }, - - /** - * Determines if the silent authentication process should be prevented - * based on environment or browser as external dependencies are required. - * @return {AuthSilentType} - */ - getAuthSilentType: () => { - const serverData = NeonEnvironment.getNeonServerData(); - if (serverData - && (typeof serverData.NeonAuthSilentType === 'string') - && (serverData.NeonAuthSilentType.length > 0)) { - return serverData.NeonAuthSilentType; - } - return AuthSilentType.DISABLED; - }, - - getFullApiPath: (path = '') => { - const host = NeonEnvironment.getHost(); - // Root path (e.g. '/api/v0') doesn't apply to legacy download/manifest-related paths. - const root = ['aopDownload', 'download', 'manifest'].includes(path) ? '' : NeonEnvironment.getRootApiPath(); - return NeonEnvironment.getApiPath[path] - ? `${host}${root}${NeonEnvironment.getApiPath[path]()}` - : `${host}${root}`; - }, - - getFullJsonLdApiPath: (path = '') => { - const host = NeonEnvironment.getHost(); - const root = NeonEnvironment.getRootJsonLdPath(); - let appliedPath = ''; - if (['products', 'prototype'].includes(path)) { - appliedPath = NeonEnvironment.getApiPath[path](); - } else if (typeof NeonEnvironment.getApiLdPath[path] === 'function') { - appliedPath = NeonEnvironment.getApiLdPath[path](); - } - return appliedPath - ? `${host}${root}${appliedPath}` - : `${host}${root}`; - }, - - getFullPagePath: (path = '') => { - const host = NeonEnvironment.getHost(); - return NeonEnvironment.getPagePath[path] - ? `${host}${NeonEnvironment.getPagePath[path]()}` - : `${host}`; - }, - - /** - * Creates the full auth path from the host and path. - * Auth path refers to /auth0. - * @param {string} path - The path to build from - */ - getFullAuthPath: (path = '') => { - const host = NeonEnvironment.getHost(); - return NeonEnvironment.getAuthPath[path] - ? `${host}${NeonEnvironment.getAuthPath[path]()}` - : `${host}`; - }, - - /** - * Creates the full auth API path from the host and path. - * Auth API path refers to /api/auth/v0. - * @param {string} path - The path to build from - * @param {boolean} useWs - Option to build a websocket path - */ - getFullAuthApiPath: (path = '', useWs = false) => { - const host = useWs - ? NeonEnvironment.getWebSocketHost() - : NeonEnvironment.getHost(); - const root = NeonEnvironment.getRootAuthApiPath(); - const appliedPath = Object.keys(NeonEnvironment.getAuthApiPath).includes(path) - ? NeonEnvironment.getAuthApiPath[path]() - : ''; - return appliedPath - ? `${host}${root}${appliedPath}` - : `${host}${root}`; - }, - - getFullGraphqlPath: () => { - const host = NeonEnvironment.getHost(); - return `${host}${NeonEnvironment.getRootGraphqlPath()}`; - }, -}; - -Object.freeze(NeonEnvironment); - -export default NeonEnvironment; diff --git a/src/lib_components/components/NeonEnvironment/NeonEnvironment.ts b/src/lib_components/components/NeonEnvironment/NeonEnvironment.ts new file mode 100644 index 00000000..8610e945 --- /dev/null +++ b/src/lib_components/components/NeonEnvironment/NeonEnvironment.ts @@ -0,0 +1,532 @@ +import { AuthSilentType, Undef } from '../../types/core'; + +// Default hosts +export const DEFAULT_API_HOST = 'https://data.neonscience.org'; +export const DEFAULT_WEB_HOST = 'https://www.neonscience.org'; + +interface IHostRegexService { + getApiHostRegex: () => RegExp; + getWebHostRegex: () => RegExp; + getDataCiteApiHostRegex: () => RegExp; +} +export const HostRegexService: IHostRegexService = { + getApiHostRegex: (): RegExp => ( + new RegExp(/^(data|cert-data|int-data|local-data)[.]neonscience[.]org$/) + ), + getWebHostRegex: (): RegExp => ( + new RegExp(/^(www|cert-www|int-www|local-www)[.](neonscience[.]org|.+[.]us-[0-9]{1}[.]platformsh[.]site)$/) + ), + getDataCiteApiHostRegex: (): RegExp => ( + new RegExp(/^(api|api[.]test)[.]datacite[.]org$/) + ), +}; + +// Names of all environment variables that MUST be explicitly defined for the +// environment to be reported as "valid". These are evnironment variables +// that are expected to be referenced by all apps. Standard vars present in all +// node environments (e.g. PORT, NODE_ENV, etc.) are not listed here. +export const requiredEnvironmentVars = [ + 'REACT_APP_NEON_PATH_API', + 'REACT_APP_NEON_PATH_PUBLIC_GRAPHQL', + 'REACT_APP_NEON_PATH_AUTH_API', + 'REACT_APP_NEON_PATH_AUTH0_API', + 'REACT_APP_NEON_ROUTER_BASE', + 'REACT_APP_NEON_ROUTER_BASE_HOME', +]; + +// Names of additional environment variables that may be referenced by +// this module depending on a given app's use case. Along with the above +// required list this makes a complete set of all environment variables +// this module will ever reference. +export const optionalEnvironmentVars = [ + 'REACT_APP_NEON_PATH_LD_API', + 'REACT_APP_NEON_PATH_DOWNLOAD_API', + 'REACT_APP_NEON_AUTH_DISABLE_WS', + 'REACT_APP_NEON_USE_GRAPHQL', + 'REACT_APP_NEON_SHOW_AOP_VIEWER', + 'REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL', + 'REACT_APP_NEON_VISUS_IFRAME_BASE_URL', + 'REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST', + 'REACT_APP_NEON_API_HOST_OVERRIDE', + 'REACT_APP_NEON_WEB_HOST_OVERRIDE', + 'REACT_APP_NEON_WS_HOST_OVERRIDE', + 'REACT_APP_NEON_DATA_CITE_API_HOST_OVERRIDE', +]; + +const EnvType = { + DEV: 'development', + PROD: 'production', +}; + +export interface NeonServerData { + NeonPublicAPIHost: Undef; + NeonWebHost: Undef; + NeonPublicAPITokenHeader: Undef; + NeonPublicAPIToken: Undef; + NeonAuthSilentType: Undef; + DataCiteAPIHost: Undef; +} + +export interface INeonEnvironment { + isValid: boolean; + isDevEnv: boolean; + isProdEnv: boolean; + useGraphql: boolean; + showAopViewer: boolean; + authDisableWs: boolean; + + getRootApiPath: () => string; + getRootGraphqlPath: () => string; + getRootJsonLdPath: () => string; + getRootAuthApiPath: () => string; + getRootAuth0ApiPath: () => string; + getRootDownloadApiPath: () => string; + + getApiPath: Record string>; + getApiLdPath: Record string>; + getAuthApiPath: Record string>; + getDownloadApiPath: Record string>; + + getAuthPath: Record string>; + + authTopics: Record string>; + + getVisusProductsBaseUrl: () => Undef; + getVisusIframeBaseUrl: () => Undef; + getDataCiteApiHostDefault: () => string; + + getRouterBasePath: () => string; + getRouterBaseHomePath: () => string; + + getApiHostOverride: () => string; + getWebHostOverride: () => string; + getWsHostOverride: () => string; + getDataCiteApiHostOverride: () => Undef; + + route: Record string>; + + getNeonServerData: () => NeonServerData|null; + getNeonServerDataWebHost: () => string|null; + getNeonServerDataApiHost: () => string|null; + getNeonServerDataDataCiteApiHost: () => string|null; + getWebHost: () => string; + getApiHost: () => string; + getWebSocketHost: () => string; + getDataCiteApiHost: () => string; + + isApiHostValid: (host: string) => boolean; + isWebHostValid: (host: string) => boolean; + isDataCiteApiHostValid: (host: string) => boolean; + + getApiTokenHeader: () => string; + getApiToken: () => string; + getAuthSilentType: () => AuthSilentType; + + getFullApiPath: (path: string) => string; + getFullJsonLdApiPath: (path: string) => string; + getFullAuthApiPath: (path: string, useWs: boolean) => string; + getFullGraphqlPath: () => string; + getFullDownloadApiPath: (path: string) => string; + + getFullAuthPath: (path: string) => string; +} + +const NeonEnvironment: INeonEnvironment = { + isValid: requiredEnvironmentVars.every((envVar) => typeof process.env[envVar] !== 'undefined'), + isDevEnv: process.env.NODE_ENV === EnvType.DEV, + isProdEnv: process.env.NODE_ENV === EnvType.PROD, + useGraphql: process.env.REACT_APP_NEON_USE_GRAPHQL === 'true', + showAopViewer: process.env.REACT_APP_NEON_SHOW_AOP_VIEWER === 'true', + authDisableWs: process.env.REACT_APP_NEON_AUTH_DISABLE_WS === 'true', + + getRootApiPath: () => process.env.REACT_APP_NEON_PATH_API || '/api/v0', + getRootGraphqlPath: () => process.env.REACT_APP_NEON_PATH_PUBLIC_GRAPHQL || '/graphql', + getRootJsonLdPath: () => `${NeonEnvironment.getRootApiPath()}${process.env.REACT_APP_NEON_PATH_LD_API}`, + getRootAuthApiPath: () => process.env.REACT_APP_NEON_PATH_AUTH_API || '/api/auth/v0', + getRootAuth0ApiPath: () => process.env.REACT_APP_NEON_PATH_AUTH0_API || '/auth0', + getRootDownloadApiPath: () => process.env.REACT_APP_NEON_PATH_DOWNLOAD_API || '/api/download/v0', + + getApiPath: { + data: (): string => '/data', + prototype: (): string => '/prototype', + documents: (): string => '/documents', + products: (): string => '/products', + releases: (): string => '/releases', + sites: (): string => '/sites', + locations: (): string => '/locations', + samples: (): string => '/samples', + taxonomy: (): string => '/taxonomy', + taxonomyDownload: (): string => '/taxonomy/download', + arcgisAssets: (): string => '/arcgis-assets', + }, + + getDownloadApiPath: { + downloadStream: (): string => '/stream', + manifestRollup: (): string => '/manifest/rollup', + prototypeDownloadStream: (): string => '/prototype/stream', + prototypeManifestRollup: (): string => '/prototype/manifest/rollup', + }, + + getApiLdPath: { + repo: (): string => '/repository', + }, + + getAuthPath: { + login: () => `${NeonEnvironment.getRootAuth0ApiPath()}/login`, + logout: () => `${NeonEnvironment.getRootAuth0ApiPath()}/logout`, + userInfo: () => `${NeonEnvironment.getRootAuth0ApiPath()}/userinfo`, + seamlessLogin: () => `${NeonEnvironment.getAuthPath.login()}?seamless=true`, + silentLogin: () => `${NeonEnvironment.getAuthPath.login()}?silent=true`, + silentLogout: () => `${NeonEnvironment.getAuthPath.logout()}?silent=true`, + notifications: () => `${NeonEnvironment.getRootAuth0ApiPath()}/liferaynotifications`, + }, + getAuthApiPath: { + ws: () => '/ws', + }, + authTopics: { + getAuth0: () => '/consumer/topic/auth0', + }, + + getVisusProductsBaseUrl: (): Undef => process.env.REACT_APP_NEON_VISUS_PRODUCTS_BASE_URL, + getVisusIframeBaseUrl: (): Undef => process.env.REACT_APP_NEON_VISUS_IFRAME_BASE_URL, + + getDataCiteApiHostDefault: (): string => ( + process.env.REACT_APP_NEON_DEFAULT_DATA_CITE_API_HOST || '' + ), + + getRouterBasePath: (): string => process.env.REACT_APP_NEON_ROUTER_BASE || '', + getRouterBaseHomePath: (): string => process.env.REACT_APP_NEON_ROUTER_BASE_HOME || '', + + getApiHostOverride: (): string => ( + process.env.REACT_APP_NEON_API_HOST_OVERRIDE || DEFAULT_API_HOST + ), + getWebHostOverride: (): string => ( + process.env.REACT_APP_NEON_WEB_HOST_OVERRIDE || DEFAULT_WEB_HOST + ), + getWsHostOverride: (): string => ( + process.env.REACT_APP_NEON_WS_HOST_OVERRIDE || DEFAULT_API_HOST + ), + getDataCiteApiHostOverride: (): Undef => ( + process.env.REACT_APP_NEON_DATA_CITE_API_HOST_OVERRIDE + ), + + route: { + home: () => '/home', + account: () => '/myaccount', + getFullRoute: (route = '') => `${NeonEnvironment.getRouterBasePath()}${route}`, + buildRouteFromHost: (route = '') => ( + `${NeonEnvironment.getApiHost()}${NeonEnvironment.route.getFullRoute(route)}` + ), + buildHomeRoute: () => ( + `${NeonEnvironment.getWebHost()}${NeonEnvironment.route.home()}` + ), + buildAccountRoute: () => ( + // TODO: replace with web host once switch over happens + `${NeonEnvironment.getApiHost()}${NeonEnvironment.route.account()}` + ), + }, + + /** + * Gets the window.NEON_SERVER_DATA injected from the server environment. + * @return {Object} The structured server data object + */ + getNeonServerData: (): NeonServerData|null => { + /* eslint-disable */ + // @ts-ignore + if (typeof WorkerGlobalScope === 'function') { + // @ts-ignore + return self.NEON_SERVER_DATA ? self.NEON_SERVER_DATA : null; + } + /* eslint-enable */ + if (typeof window === 'object') { + // @ts-ignore + return window.NEON_SERVER_DATA ? window.NEON_SERVER_DATA : null; + } + return null; + }, + + getNeonServerDataWebHost: (): string|null => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData && (typeof serverData.NeonWebHost === 'string')) { + const apiHost = serverData.NeonWebHost; + try { + const { hostname: apiHostname } = new URL(apiHost); + if (NeonEnvironment.isWebHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse web host as URL', [e]); + } + } + return null; + }, + + getNeonServerDataApiHost: (): string|null => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData && (typeof serverData.NeonPublicAPIHost === 'string')) { + const apiHost = serverData.NeonPublicAPIHost; + try { + const { hostname: apiHostname } = new URL(apiHost); + if (NeonEnvironment.isApiHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse API host as URL', [e]); + } + } + return null; + }, + + getNeonServerDataDataCiteApiHost: (): string|null => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData && (typeof serverData.DataCiteAPIHost === 'string')) { + const apiHost = serverData.DataCiteAPIHost; + try { + const { hostname: apiHostname } = new URL(apiHost); + if (NeonEnvironment.isDataCiteApiHostValid(apiHostname)) { + return apiHost; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse DataCite API host as URL', [e]); + } + } + return null; + }, + + getWebHost: (): string => { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getWebHostOverride()) { + return NeonEnvironment.getWebHostOverride(); + } + // Check for server data env var + const webHost: string|null = NeonEnvironment.getNeonServerDataWebHost(); + if (webHost !== null) { + return webHost; + } + /* eslint-disable */ + // @ts-ignore + if (typeof WorkerGlobalScope === 'function' && typeof self.location === 'object') { + if (NeonEnvironment.isWebHostValid(self.location.host)) { + return `${self.location.protocol}//${self.location.host}`; + } + return DEFAULT_WEB_HOST; + } + /* eslint-enable */ + if (NeonEnvironment.isWebHostValid(window.location.host)) { + return `${window.location.protocol}//${window.location.host}`; + } + return DEFAULT_WEB_HOST; + }, + + getApiHost: (): string => { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getApiHostOverride()) { + return NeonEnvironment.getApiHostOverride(); + } + // Check for server data env var + const apiHost: string|null = NeonEnvironment.getNeonServerDataApiHost(); + if (apiHost !== null) { + return apiHost; + } + /* eslint-disable */ + // @ts-ignore + if (typeof WorkerGlobalScope === 'function' && typeof self.location === 'object') { + if (NeonEnvironment.isApiHostValid(self.location.host)) { + return `${self.location.protocol}//${self.location.host}`; + } + return DEFAULT_API_HOST; + } + /* eslint-enable */ + if (NeonEnvironment.isApiHostValid(window.location.host)) { + return `${window.location.protocol}//${window.location.host}`; + } + return DEFAULT_API_HOST; + }, + + getWebSocketHost: (): string => { + if (NeonEnvironment.isDevEnv && NeonEnvironment.getWsHostOverride()) { + return NeonEnvironment.getWsHostOverride(); + } + const apiHost = NeonEnvironment.getApiHost(); + const hostUrl = new URL(apiHost); + const { protocol: apiProtocol, hostname: apiHostname } = hostUrl; + return apiProtocol.startsWith('https') + ? `wss://${apiHostname}` + : `ws://${apiHostname}`; + }, + + getDataCiteApiHost: (): string => { + // Check for local override + if (NeonEnvironment.isDevEnv && NeonEnvironment.getDataCiteApiHostOverride()) { + return NeonEnvironment.getDataCiteApiHostOverride() as string; + } + // Check for server data env var + const apiHost: string|null = NeonEnvironment.getNeonServerDataDataCiteApiHost(); + if (apiHost !== null) { + return apiHost; + } + return NeonEnvironment.getDataCiteApiHostDefault(); + }, + + /** + * Valid host names include localhost and known NEON hosts + * @param host + * @returns + */ + isApiHostValid: (host: string): boolean => { + if ((typeof host !== 'string') || (host.length <= 0)) { + return false; + } + const regex = HostRegexService.getApiHostRegex(); + if (!regex) return false; + const matches = regex.exec(host); + if (!matches) return false; + return (matches.length > 0); + }, + + /** + * Valid host names include localhost and known NEON hosts + * @param host + * @returns + */ + isWebHostValid: (host: string): boolean => { + if ((typeof host !== 'string') || (host.length <= 0)) { + return false; + } + const regex = HostRegexService.getWebHostRegex(); + if (!regex) return false; + const matches = regex.exec(host); + if (!matches) return false; + return (matches.length > 0); + }, + + /** + * Validate the data cite API host + * @param host + * @returns + */ + isDataCiteApiHostValid: (host: string): boolean => { + if ((typeof host !== 'string') || (host.length <= 0)) { + return false; + } + const regex = HostRegexService.getDataCiteApiHostRegex(); + if (!regex) return false; + const matches = regex.exec(host); + if (!matches) return false; + return (matches.length > 0); + }, + + /** + * Gets the API token header name + * @return {string} The API token header name + */ + getApiTokenHeader: (): string => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData && (typeof serverData.NeonPublicAPITokenHeader === 'string')) { + return serverData.NeonPublicAPITokenHeader; + } + return ''; + }, + + /** + * Gets the API token value + * @return {string} The API token value + */ + getApiToken: (): string => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData && (typeof serverData.NeonPublicAPIToken === 'string')) { + return serverData.NeonPublicAPIToken; + } + return ''; + }, + + /** + * Determines if the silent authentication process should be prevented + * based on environment or browser as external dependencies are required. + * @return {AuthSilentType} + */ + getAuthSilentType: (): AuthSilentType => { + const serverData = NeonEnvironment.getNeonServerData(); + if (serverData + && (typeof serverData.NeonAuthSilentType === 'string') + && (serverData.NeonAuthSilentType.length > 0)) { + return serverData.NeonAuthSilentType as AuthSilentType; + } + return AuthSilentType.DISABLED; + }, + + getFullApiPath: (path: string = ''): string => { + const host = NeonEnvironment.getApiHost(); + const root = ['download', 'manifest'].includes(path) + ? '' + : NeonEnvironment.getRootApiPath(); + return NeonEnvironment.getApiPath[path] + ? `${host}${root}${NeonEnvironment.getApiPath[path]()}` + : `${host}${root}`; + }, + + getFullDownloadApiPath: (path: string = ''): string => { + const host = NeonEnvironment.getApiHost(); + const root = NeonEnvironment.getRootDownloadApiPath(); + return NeonEnvironment.getDownloadApiPath[path] + ? `${host}${root}${NeonEnvironment.getDownloadApiPath[path]()}` + : `${host}${root}`; + }, + + getFullJsonLdApiPath: (path: string = ''): string => { + const host = NeonEnvironment.getApiHost(); + const root = NeonEnvironment.getRootJsonLdPath(); + let appliedPath = ''; + if (['products', 'prototype'].includes(path)) { + appliedPath = NeonEnvironment.getApiPath[path](); + } else if (typeof NeonEnvironment.getApiLdPath[path] === 'function') { + appliedPath = NeonEnvironment.getApiLdPath[path](); + } + return appliedPath + ? `${host}${root}${appliedPath}` + : `${host}${root}`; + }, + + /** + * Creates the full auth path from the host and path. + * Auth path refers to /auth0. + * @param {string} path - The path to build from + */ + getFullAuthPath: (path: string = ''): string => { + const host = NeonEnvironment.getApiHost(); + return NeonEnvironment.getAuthPath[path] + ? `${host}${NeonEnvironment.getAuthPath[path]()}` + : `${host}`; + }, + + /** + * Creates the full auth API path from the host and path. + * Auth API path refers to /api/auth/v0. + * @param {string} path - The path to build from + * @param {boolean} useWs - Option to build a websocket path + */ + getFullAuthApiPath: (path: string = '', useWs: boolean = false): string => { + const host = useWs + ? NeonEnvironment.getWebSocketHost() + : NeonEnvironment.getApiHost(); + const root = NeonEnvironment.getRootAuthApiPath(); + const appliedPath = Object.keys(NeonEnvironment.getAuthApiPath).includes(path) + ? NeonEnvironment.getAuthApiPath[path]() + : ''; + return appliedPath + ? `${host}${root}${appliedPath}` + : `${host}${root}`; + }, + + getFullGraphqlPath: (): string => { + const host = NeonEnvironment.getApiHost(); + return `${host}${NeonEnvironment.getRootGraphqlPath()}`; + }, +}; + +Object.freeze(NeonEnvironment); + +export default NeonEnvironment; diff --git a/src/lib_components/components/NeonEnvironment/__tests__/NeonEnvironment.js b/src/lib_components/components/NeonEnvironment/__tests__/NeonEnvironment.js index 48944fb1..1f4a66dd 100644 --- a/src/lib_components/components/NeonEnvironment/__tests__/NeonEnvironment.js +++ b/src/lib_components/components/NeonEnvironment/__tests__/NeonEnvironment.js @@ -12,7 +12,6 @@ describe('NeonEnvironment', () => { 'isValid', 'isDevEnv', 'isProdEnv', - 'isForeignEnv', 'useGraphql', 'showAopViewer', 'authDisableWs', @@ -25,17 +24,17 @@ describe('NeonEnvironment', () => { describe('simple string access methods', () => { [ - 'getApiName', - 'getApiVersion', 'getRootApiPath', 'getRootGraphqlPath', 'getRootJsonLdPath', 'getRootAuthApiPath', + 'getRootAuth0ApiPath', + 'getRootDownloadApiPath', 'getVisusProductsBaseUrl', 'getVisusIframeBaseUrl', 'getRouterBasePath', 'getRouterBaseHomePath', - 'getHostOverride', + 'getApiHostOverride', 'getWsHostOverride', ].forEach((method) => { test(`${method}()`, () => { @@ -48,9 +47,9 @@ describe('NeonEnvironment', () => { [ 'getApiPath', 'getApiLdPath', - 'getPagePath', 'getAuthPath', 'getAuthApiPath', + 'getDownloadApiPath', 'authTopics', 'route', ].forEach((methodGroup) => { @@ -66,16 +65,16 @@ describe('NeonEnvironment', () => { describe('get full path methods', () => { test('getFullApiPath()', () => { - const host = NeonEnvironment.getHost(); + const host = NeonEnvironment.getApiHost(); const fullPath1 = NeonEnvironment.getFullApiPath(); expect(fullPath1.startsWith(host)).toBe(true); - const downloadPath = NeonEnvironment.getApiPath.download(); - const fullPath2 = NeonEnvironment.getFullApiPath('download'); + const productPath = NeonEnvironment.getApiPath.products(); + const fullPath2 = NeonEnvironment.getFullApiPath('products'); expect(fullPath2.startsWith(host)).toBe(true); - expect(fullPath2.endsWith(downloadPath)).toBe(true); + expect(fullPath2.endsWith(productPath)).toBe(true); }); test('getFullJsonLdApiPath()', () => { - const host = NeonEnvironment.getHost(); + const host = NeonEnvironment.getApiHost(); const fullPath1 = NeonEnvironment.getFullJsonLdApiPath(); expect(fullPath1.startsWith(host)).toBe(true); const productsPath = NeonEnvironment.getApiPath.products(); @@ -87,17 +86,8 @@ describe('NeonEnvironment', () => { expect(fullPath3.startsWith(host)).toBe(true); expect(fullPath3.endsWith(repoPath)).toBe(true); }); - test('getFullPagePath()', () => { - const host = NeonEnvironment.getHost(); - const fullPath1 = NeonEnvironment.getFullPagePath(); - expect(fullPath1.startsWith(host)).toBe(true); - const fileNamingConventionsPath = NeonEnvironment.getPagePath.fileNamingConventions(); - const fullPath2 = NeonEnvironment.getFullPagePath('fileNamingConventions'); - expect(fullPath2.startsWith(host)).toBe(true); - expect(fullPath2.endsWith(fileNamingConventionsPath)).toBe(true); - }); test('getFullAuthPath()', () => { - const host = NeonEnvironment.getHost(); + const host = NeonEnvironment.getApiHost(); const fullPath1 = NeonEnvironment.getFullAuthPath(); expect(fullPath1.startsWith(host)).toBe(true); const loginPath = NeonEnvironment.getAuthPath.login(); @@ -107,7 +97,7 @@ describe('NeonEnvironment', () => { }); test('getFullAuthApiPath()', () => { const wsPath = NeonEnvironment.getAuthApiPath.ws(); - const host1 = NeonEnvironment.getHost(); + const host1 = NeonEnvironment.getApiHost(); const fullPath1 = NeonEnvironment.getFullAuthApiPath(); expect(fullPath1.startsWith(host1)).toBe(true); const fullPath2 = NeonEnvironment.getFullAuthApiPath('ws'); @@ -121,7 +111,7 @@ describe('NeonEnvironment', () => { expect(fullPath4.endsWith(wsPath)).toBe(true); }); test('getFullGraphqlath()', () => { - const host = NeonEnvironment.getHost(); + const host = NeonEnvironment.getApiHost(); expect(NeonEnvironment.getFullGraphqlPath().startsWith(host)).toBe(true); }); }); diff --git a/src/lib_components/components/NeonEnvironment/package.json b/src/lib_components/components/NeonEnvironment/package.json index 7209bb46..3b9b4fd6 100644 --- a/src/lib_components/components/NeonEnvironment/package.json +++ b/src/lib_components/components/NeonEnvironment/package.json @@ -1,6 +1,6 @@ { "private": true, "name": "neon-environment", - "main": "./NeonEnvironment.js", - "module": "./NeonEnvironment.js" + "main": "./NeonEnvironment.ts", + "module": "./NeonEnvironment.ts" } diff --git a/src/lib_components/components/NeonHeader/ApplicationMenu.tsx b/src/lib_components/components/NeonHeader/ApplicationMenu.tsx index eb4ba47c..8b9cdd53 100644 --- a/src/lib_components/components/NeonHeader/ApplicationMenu.tsx +++ b/src/lib_components/components/NeonHeader/ApplicationMenu.tsx @@ -103,12 +103,12 @@ const Menu = (props: MenuProps) => { }; // open menu by tab key - function handleMenuKeyDown(event: React.KeyboardEvent) { + const handleMenuKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Tab') { event.preventDefault(); setOpen(false); } - } + }; // handle a menu selection const handleMenuItemClick = (event: React.MouseEvent, url: string) => { @@ -189,7 +189,11 @@ const Menu = (props: MenuProps) => { ); }; -export default function ApplicationMenu() { +/** + * Return the application menu + * @returns The menu or null if the user has no applications to display. + */ +const ApplicationMenu = () => { const [{ auth: authData }] = NeonContext.useNeonContextState(); const apps: UserApp[] = authData?.userData?.data?.apps; if (apps?.length > 0) { @@ -198,4 +202,6 @@ export default function ApplicationMenu() { ); } return (null); -} +}; + +export default ApplicationMenu; diff --git a/src/lib_components/components/NeonHeader/NeonHeader.jsx b/src/lib_components/components/NeonHeader/NeonHeader.jsx index 302eb4f0..03d9d451 100644 --- a/src/lib_components/components/NeonHeader/NeonHeader.jsx +++ b/src/lib_components/components/NeonHeader/NeonHeader.jsx @@ -243,7 +243,7 @@ const useStyles = makeStyles((theme) => ({ })); const buildSearchAction = (action) => { - const root = 'https://www.neonscience.org'; + const root = NeonEnvironment.getWebHost(); if (!action) return `${root}/search/site`; if (action.startsWith('/')) { return `${root}${action}`; diff --git a/src/lib_components/components/ReleaseFilter/ReleaseFilter.jsx b/src/lib_components/components/ReleaseFilter/ReleaseFilter.jsx index 73370b6e..c945fd04 100644 --- a/src/lib_components/components/ReleaseFilter/ReleaseFilter.jsx +++ b/src/lib_components/components/ReleaseFilter/ReleaseFilter.jsx @@ -23,6 +23,8 @@ import InfoIcon from '@material-ui/icons/InfoOutlined'; import Theme from '../Theme/Theme'; +import RouteService from '../../service/RouteService'; + const useStyles = makeStyles((theme) => ({ title: { fontWeight: 500, @@ -92,7 +94,6 @@ const useStyles = makeStyles((theme) => ({ const UNSPECIFIED_NAME = 'Latest and Provisional'; const UNSPECIFIED_DESCRIPTION = 'Data in the latest release in addition to provisional data (not yet in any release)'; const DOI_TITLE = 'Digital Object Identifier (DOI) - A citable permanent link to this this data product release'; -const INFO_URL = 'https://www.neonscience.org/data-samples/data-management/data-revisions-releases'; const formatGenerationDate = (generationDate) => { const generationMoment = moment.utc(generationDate); @@ -164,7 +165,7 @@ const ReleaseFilter = (props) => { ); const releasesLink = ( - + Data Product Revisions and Releases ); diff --git a/src/lib_components/components/SiteMap/SiteMapContext.jsx b/src/lib_components/components/SiteMap/SiteMapContext.jsx index ce5c645a..2172688d 100644 --- a/src/lib_components/components/SiteMap/SiteMapContext.jsx +++ b/src/lib_components/components/SiteMap/SiteMapContext.jsx @@ -371,6 +371,24 @@ const updateMapTileWithZoom = (state) => { return newState; }; +/** + * Calculates the zoom state from the specified zoom + * @param {number} zoom + * @param {Object} newState + * @param {boolean} init + * @return The updated map state + */ +const calculateZoomState = (zoom, newState, init = false) => { + let appliedState = newState; + appliedState.map.zoomedIcons = getZoomedIcons(zoom); + appliedState = updateMapTileWithZoom(appliedState); + if (!init) { + appliedState = calculateFeatureAvailability(appliedState); + appliedState = calculateFeatureDataFetches(appliedState); + } + return appliedState; +}; + // Increment the completed count for overall fetch and, if completed and expected are now equal, // reset both (so that subsequent batches of fetches can give an accurate progress metric). const completeOverallFetch = (state) => { @@ -645,10 +663,7 @@ const reducer = (state, action) => { newState.map.zoom = action.zoom; if (centerIsValid(action.center)) { newState.map.center = action.center; } if (boundsAreValid(action.bounds)) { newState.map.bounds = action.bounds; } - newState.map.zoomedIcons = getZoomedIcons(newState.map.zoom); - newState = updateMapTileWithZoom(newState); - newState = calculateFeatureAvailability(newState); - newState = calculateFeatureDataFetches(newState); + newState = calculateZoomState(action.zoom, newState); return newState; case 'setMapBounds': @@ -1056,6 +1071,10 @@ const Provider = (props) => { if (neonContextIsFinal && !neonContextHasError) { initialState = hydrateNeonContextData(initialState, neonContextData); } + const hasInitialZoom = (typeof mapZoom === 'number') && zoomIsValid(mapZoom); + if (hasInitialZoom) { + initialState = calculateZoomState(initialMapZoom, initialState, true); + } const [state, dispatch] = useReducer(reducer, initialState); const canFetchFeatureData = ( diff --git a/src/lib_components/components/SiteMap/SiteMapLeaflet.jsx b/src/lib_components/components/SiteMap/SiteMapLeaflet.jsx index dc514668..7ee0695a 100644 --- a/src/lib_components/components/SiteMap/SiteMapLeaflet.jsx +++ b/src/lib_components/components/SiteMap/SiteMapLeaflet.jsx @@ -262,6 +262,8 @@ const SiteMapLeaflet = () => { && state.focusLocation.fetch.status !== FETCH_STATUS.SUCCESS ) { canRender = false; } + const [mapRefReady, setMapRefReady] = useState(false); + /** Effect If zoom was not set as a prop then attempt to set the initial zoom such that @@ -285,18 +287,33 @@ const SiteMapLeaflet = () => { Effect If map bounds are null (as they will be when setting a focus location) then fill them in We have to do it this way as only the Leaflet Map instance can give us bounds + + Effect for setting the initial zoom so that we can include the bounds + of the map in the initial zoom setting to allow proper feature detection. */ + const mapRefExistsProp = mapRefExists(); useEffect(() => { - if (state.map.bounds !== null || !mapRefExists()) { return; } + if (state.map.bounds !== null || !mapRefExistsProp) { return; } const bounds = mapRef.current.leafletElement.getBounds(); - dispatch({ - type: 'setMapBounds', - bounds: { - lat: [bounds._southWest.lat, bounds._northEast.lat], - lng: [bounds._southWest.lng, bounds._northEast.lng], - }, - }); - }, [state.map.bounds, dispatch]); + if (state.map.zoom === null) { + dispatch({ + type: 'setMapBounds', + bounds: { + lat: [bounds._southWest.lat, bounds._northEast.lat], + lng: [bounds._southWest.lng, bounds._northEast.lng], + }, + }); + } else { + dispatch({ + type: 'setMapZoom', + zoom: state.map.zoom, + bounds: { + lat: [bounds._southWest.lat, bounds._northEast.lat], + lng: [bounds._southWest.lng, bounds._northEast.lng], + }, + }); + } + }, [mapRefExistsProp, state.map.bounds, state.map.zoom, dispatch]); /** Effect @@ -432,7 +449,6 @@ const SiteMapLeaflet = () => { as a prop. Thus we must track whether it has rendered with local state. We want to basically re-render the map immediately and only once when the mepRef is set through the first render. */ - const [mapRefReady, setMapRefReady] = useState(false); useEffect(() => { // eslint-disable-line react-hooks/exhaustive-deps if (mapRefExists() && !mapRefReady) { setMapRefReady(true); diff --git a/src/lib_components/components/SiteMap/SiteMapTable.jsx b/src/lib_components/components/SiteMap/SiteMapTable.jsx index ffdbc416..1b5c273f 100644 --- a/src/lib_components/components/SiteMap/SiteMapTable.jsx +++ b/src/lib_components/components/SiteMap/SiteMapTable.jsx @@ -627,7 +627,7 @@ const SiteMapTable = () => { onClick={() => jumpTo(domain.domainCode)} title={`Click to view ${domain.domainCode} on the map`} > - {domain.domainCode} + {domain.domainCode || ''} ); @@ -671,7 +671,7 @@ const SiteMapTable = () => { onClick={() => jumpTo(stateCode)} title={`Click to view ${stateCode} on the map`} > - {usstate.name} + {usstate.name || ''} ); @@ -779,7 +779,7 @@ const SiteMapTable = () => { onClick={() => jumpTo(name)} title={`View ${name} on map`} > - {name} + {name || ''} ); }, diff --git a/src/lib_components/components/SiteMap/SiteMapUtils.js b/src/lib_components/components/SiteMap/SiteMapUtils.js index 775741c9..5e0af590 100644 --- a/src/lib_components/components/SiteMap/SiteMapUtils.js +++ b/src/lib_components/components/SiteMap/SiteMapUtils.js @@ -6,6 +6,8 @@ import L from 'leaflet'; import { COLORS } from '../Theme/Theme'; +import RouteService from '../../service/RouteService'; + // SVGs for all map icons import iconPlaceholderSVG from './svg/icon-placeholder.svg'; @@ -1188,7 +1190,7 @@ export const calculateFeatureAvailability = (state) => { Used to construction URLs when linking out to other pages */ export const getHref = (key, arg = null) => { - const EXPLORE_DATA_PRODUCTS_BASE = 'https://data.neonscience.org/data-products/explore'; + const EXPLORE_DATA_PRODUCTS_BASE = RouteService.getDataProductExplorePath(); if ((arg || '').length === 0) { return '#'; } switch (key) { case 'EXPLORE_DATA_PRODUCTS_BY_SITE': @@ -1198,9 +1200,9 @@ export const getHref = (key, arg = null) => { case 'EXPLORE_DATA_PRODUCTS_BY_DOMAIN': return `${EXPLORE_DATA_PRODUCTS_BASE}?domain=${arg}`; case 'SITE_DETAILS': - return `https://www.neonscience.org/field-sites/${arg}`; + return RouteService.getFieldSiteDetailPath(arg); case 'DOMAIN_DETAILS': - return `https://www.neonscience.org/domains/${arg}`; + return RouteService.getDomainDetailPath(arg); default: return '#'; } diff --git a/src/lib_components/components/SiteMap/StyleGuide.jsx b/src/lib_components/components/SiteMap/StyleGuide.jsx index 69cc0128..fe116e47 100644 --- a/src/lib_components/components/SiteMap/StyleGuide.jsx +++ b/src/lib_components/components/SiteMap/StyleGuide.jsx @@ -415,6 +415,7 @@ import SiteMap from 'portal-core-components/lib/components/SiteMap'; scrollButtons="auto" > + @@ -442,8 +443,26 @@ import SiteMap from 'portal-core-components/lib/components/SiteMap'; )} - {/* 1: Selection */} + {/* 1: Basic */} {tabValue !== 1 ? null : ( +
+ Zoom + + Preset zoom value via the mapZoom property. + + + + + + {` + + `} + +
+ )} + + {/* 2: Selection */} + {tabValue !== 2 ? null : (
Selection @@ -462,8 +481,8 @@ import SiteMap from 'portal-core-components/lib/components/SiteMap';
)} - {/* 2: Focus Location */} - {tabValue !== 2 ? null : ( + {/* 3: Focus Location */} + {tabValue !== 3 ? null : (
Focus Location @@ -483,8 +502,8 @@ import SiteMap from 'portal-core-components/lib/components/SiteMap';
)} - {/* 3: Full Height Table */} - {tabValue !== 3 ? null : ( + {/* 4: Full Height Table */} + {tabValue !== 4 ? null : (
Full Height Table @@ -504,8 +523,8 @@ import SiteMap from 'portal-core-components/lib/components/SiteMap';
)} - {/* 4: Manual Locations */} - {tabValue !== 4 ? null : ( + {/* 5: Manual Locations */} + {tabValue !== 5 ? null : (
Manual Locations @@ -559,8 +578,8 @@ return (
)} - {/* 5: Split View */} - {tabValue !== 5 ? null : ( + {/* 6: Split View */} + {tabValue !== 6 ? null : (
Split View diff --git a/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContainer.jsx b/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContainer.jsx index db5c0462..8107cc66 100644 --- a/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContainer.jsx +++ b/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContainer.jsx @@ -23,9 +23,10 @@ import DateRangeIcon from '@material-ui/icons/DateRange'; import VariablesIcon from '@material-ui/icons/Timeline'; import AxesIcon from '@material-ui/icons/BorderInner'; -import NeonEnvironment from '../NeonEnvironment/NeonEnvironment'; import Theme, { COLORS } from '../Theme/Theme'; +import RouteService from '../../service/RouteService'; + import TimeSeriesViewerContext, { summarizeTimeSteps, TIME_SERIES_VIEWER_STATUS, @@ -203,7 +204,7 @@ export function TimeSeriesViewerSummary() { }; // Product - const productHref = `${NeonEnvironment.getHost()}/data-products/${state.product.productCode}`; + const productHref = RouteService.getProductDetailPath(state.product.productCode); let productSummaryTitle = (
Data Product diff --git a/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContext.jsx b/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContext.jsx index e29332aa..672dcb94 100644 --- a/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContext.jsx +++ b/src/lib_components/components/TimeSeriesViewer/TimeSeriesViewerContext.jsx @@ -166,6 +166,7 @@ export const DEFAULT_STATE = { continuousDateRange: [], sites: {}, }, + release: null, graphData: { data: [], qualityData: [], @@ -1140,6 +1141,7 @@ const Provider = (props) => { mode: modeProp, productCode: productCodeProp, productData: productDataProp, + release: releaseProp, children, } = props; @@ -1159,6 +1161,7 @@ const Provider = (props) => { } else { initialState.product.productCode = productCodeProp; } + initialState.release = releaseProp; initialState.selection = applyDefaultsToSelection(initialState); const [state, dispatch] = useReducer(reducer, initialState); @@ -1182,7 +1185,7 @@ const Provider = (props) => { if (state.status !== TIME_SERIES_VIEWER_STATUS.INIT_PRODUCT) { return; } if (state.fetchProduct.status !== FETCH_STATUS.AWAITING_CALL) { return; } dispatch({ type: 'initFetchProductCalled' }); - NeonGraphQL.getDataProductByCode(state.product.productCode).pipe( + NeonGraphQL.getDataProductByCode(state.product.productCode, state.release).pipe( map((response) => { if (response.response && response.response.data && response.response.data.product) { dispatch({ @@ -1199,7 +1202,13 @@ const Provider = (props) => { return of(false); }), ).subscribe(); - }, [state.mode, state.status, state.fetchProduct.status, state.product.productCode]); + }, [ + state.mode, + state.status, + state.fetchProduct.status, + state.product.productCode, + state.release, + ]); /** Effect - Handle changes to selection @@ -1208,7 +1217,13 @@ const Provider = (props) => { useEffect(() => { const getSiteMonthDataURL = (siteCode, month) => { const root = NeonEnvironment.getFullApiPath('data'); - return `${root}/${state.product.productCode}/${siteCode}/${month}`; + const hasRelease = state.release + && (typeof state.release === 'string') + && (state.release.length > 0); + const releaseParam = hasRelease + ? `?release=${state.release}` + : ''; + return `${root}/${state.product.productCode}/${siteCode}/${month}${releaseParam}`; }; const { timeStep: selectedTimeStep, autoTimeStep } = state.selection; const timeStep = selectedTimeStep === 'auto' ? autoTimeStep : selectedTimeStep; @@ -1418,6 +1433,7 @@ const Provider = (props) => { state.selection.digest, state.variables, state.product, + state.release, ]); /** @@ -1470,6 +1486,7 @@ Provider.propTypes = { mode: PropTypes.string, productCode: TimeSeriesViewerPropTypes.productCode, productData: TimeSeriesViewerPropTypes.productData, + release: PropTypes.string, children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.node, @@ -1484,6 +1501,7 @@ Provider.defaultProps = { mode: VIEWER_MODE.DEFAULT, productCode: null, productData: null, + release: null, }; /** diff --git a/src/lib_components/components/TimeSeriesViewer/__tests__/__snapshots__/TimeSeriesViewerContainer.jsx.snap b/src/lib_components/components/TimeSeriesViewer/__tests__/__snapshots__/TimeSeriesViewerContainer.jsx.snap index 4709331f..8f05ca83 100644 --- a/src/lib_components/components/TimeSeriesViewer/__tests__/__snapshots__/TimeSeriesViewerContainer.jsx.snap +++ b/src/lib_components/components/TimeSeriesViewer/__tests__/__snapshots__/TimeSeriesViewerContainer.jsx.snap @@ -197,7 +197,7 @@ exports[`TimeSeriesViewerContainer TimeSeriesViewerSummary Renders for defined p > Excess Samples + diff --git a/src/lib_components/remoteAssetsMap/package.json b/src/lib_components/remoteAssetsMap/package.json index 65fa0632..d4e43f84 100644 --- a/src/lib_components/remoteAssetsMap/package.json +++ b/src/lib_components/remoteAssetsMap/package.json @@ -1,4 +1,4 @@ { "type": "module", - "module": "./remoteAssetsMap.js" + "module": "./remoteAssets.js" } diff --git a/src/lib_components/remoteAssetsMap/remoteAssets.js b/src/lib_components/remoteAssetsMap/remoteAssets.js new file mode 100644 index 00000000..c600b576 --- /dev/null +++ b/src/lib_components/remoteAssetsMap/remoteAssets.js @@ -0,0 +1,13 @@ +export const REMOTE_ASSET_PATHS = { + DRUPAL_THEME_CSS: '/themes/custom/neon/build/components/theme/theme.css', + DRUPAL_HEADER_JS: '/themes/custom/neon/build/components/header/header.js', + DRUPAL_HEADER_HTML: '/neon-assets/partial/header', + DRUPAL_FOOTER_HTML: '/neon-assets/partial/footer', +}; + +export const REMOTE_ASSET_NAMES = { + DRUPAL_THEME_CSS: 'drupal-theme.css', + DRUPAL_HEADER_JS: 'drupal-header.js', + DRUPAL_HEADER_HTML: 'drupal-header.html', + DRUPAL_FOOTER_HTML: 'drupal-footer.html', +}; diff --git a/src/lib_components/remoteAssetsMap/remoteAssetsMap.js b/src/lib_components/remoteAssetsMap/remoteAssetsMap.js index 95f1aafd..dfb795ce 100644 --- a/src/lib_components/remoteAssetsMap/remoteAssetsMap.js +++ b/src/lib_components/remoteAssetsMap/remoteAssetsMap.js @@ -1,21 +1,26 @@ // A structure containing local filenames and remote URLs for all remote assets used in + +import NeonEnvironment from '../components/NeonEnvironment/NeonEnvironment'; + +import { REMOTE_ASSET_PATHS, REMOTE_ASSET_NAMES } from './remoteAssets'; + // portal-core-components that we want to cache updated snapshots of at every lib build const REMOTE_ASSETS = { DRUPAL_THEME_CSS: { - name: 'drupal-theme.css', - url: 'https://www.neonscience.org/themes/custom/neon/build/components/theme/theme.css', + name: REMOTE_ASSET_NAMES.DRUPAL_THEME_CSS, + url: `${NeonEnvironment.getWebHost()}${REMOTE_ASSET_PATHS.DRUPAL_THEME_CSS}`, }, DRUPAL_HEADER_JS: { - name: 'drupal-header.js', - url: 'https://www.neonscience.org/themes/custom/neon/build/components/header/header.js', + name: REMOTE_ASSET_NAMES.DRUPAL_HEADER_JS, + url: `${NeonEnvironment.getWebHost()}${REMOTE_ASSET_PATHS.DRUPAL_HEADER_JS}`, }, DRUPAL_HEADER_HTML: { - name: 'drupal-header.html', - url: 'https://www.neonscience.org/neon-assets/partial/header', + name: REMOTE_ASSET_NAMES.DRUPAL_HEADER_HTML, + url: `${NeonEnvironment.getWebHost()}${REMOTE_ASSET_PATHS.DRUPAL_HEADER_HTML}`, }, DRUPAL_FOOTER_HTML: { - name: 'drupal-footer.html', - url: 'https://www.neonscience.org/neon-assets/partial/footer', + name: REMOTE_ASSET_NAMES.DRUPAL_FOOTER_HTML, + url: `${NeonEnvironment.getWebHost()}${REMOTE_ASSET_PATHS.DRUPAL_FOOTER_HTML}`, }, }; diff --git a/src/lib_components/service/DataCiteService.ts b/src/lib_components/service/DataCiteService.ts new file mode 100644 index 00000000..1c92019c --- /dev/null +++ b/src/lib_components/service/DataCiteService.ts @@ -0,0 +1,224 @@ +import { of } from 'rxjs'; +import { map, catchError } from 'rxjs/operators'; +import { ajax, AjaxResponse } from 'rxjs/ajax'; + +import NeonEnvironment from '../components/NeonEnvironment/NeonEnvironment'; +import { isStringNonEmpty } from '../util/typeUtil'; + +export enum CitationDownloadType { + DATA_PRODUCT = 'DATA_PRODUCT', + PROTOTYPE_DATASET = 'PROTOTYPE_DATASET', +} + +export interface CitationFormat { + shortName: string; + longName: string; + mime: string; + extension: string; + applicableDownloadtypes: CitationDownloadType[]; + generateProvisionalCitation: (product: Record) => string; + generateProtoDatasetProvisionalCitation: (dataset: Record) => string; +} + +/** + * Service for working with DataCite + */ +export interface IDataCiteService { + getDoiUrl: (doi: string, format: CitationFormat) => string; + getCitationFormats: () => CitationFormat[]; + getDataProductFormats: () => CitationFormat[]; + getPrototypeDatasetFormats: () => CitationFormat[]; + downloadCitation: ( + formatShortName: string, + type: CitationDownloadType, + target: Record, + doi: string, + release?: string, + ) => void; + executeDownload: (fileName: string, mimeType: string, payload: string) => void; +} + +const DataCiteService: IDataCiteService = { + getDoiUrl: (doi: string, format: CitationFormat): string => { + const { mime }: CitationFormat = format; + const doiId: string = doi?.split('/').slice(-2).join('/') || ''; + return `${NeonEnvironment.getDataCiteApiHost()}/dois/${mime}/${doiId}`; + }, + + getCitationFormats: (): CitationFormat[] => ([ + { + shortName: 'BibTex', + longName: 'BibTex', + mime: 'application/x-bibtex', + extension: 'bib', + applicableDownloadtypes: [ + CitationDownloadType.DATA_PRODUCT, + CitationDownloadType.PROTOTYPE_DATASET, + ], + generateProvisionalCitation: ( + product: Record, + ): string => (`@misc{${product.productCode as string}/provisional, + doi = {}, + url = {${window.location.href}}, + author = {{National Ecological Observatory Network (NEON)}}, + language = {en}, + title = {${product.productName as string} (${product.productCode as string})}, + publisher = {National Ecological Observatory Network (NEON)}, + year = {${(new Date()).getFullYear()}} +}`), + generateProtoDatasetProvisionalCitation: (dataset: Record): string => { + let id = `${dataset.uuid}/prototype`; + let doiId = ''; + let version = ''; + if (dataset.doi && (dataset.doi as Record).url) { + id = (dataset.doi as Record).url; + doiId = id.split('/').slice(-2).join('/'); + } + if (dataset.version) { + version = `, ${dataset.version as string}`; + } + return `@misc{${id}, + doi = {${doiId}}, + url = {${window.location.href}}, + author = {National Ecological Observatory Network (NEON)}, + language = {en}, + title = {${dataset.projectTitle as string}${version} (${dataset.uuid as string})}, + publisher = {National Ecological Observatory Network (NEON)}, + year = {${(new Date()).getFullYear()}} +}`; + }, + }, + { + shortName: 'RIS', + longName: 'Research Information Systems (RIS)', + mime: 'application/x-research-info-systems', + extension: 'ris', + applicableDownloadtypes: [ + CitationDownloadType.DATA_PRODUCT, + CitationDownloadType.PROTOTYPE_DATASET, + ], + generateProvisionalCitation: ( + product: Record, + ): string => (`TY - DATA +T1 - ${product.productName as string} (${product.productCode as string}) +AU - National Ecological Observatory Network (NEON) +DO - +UR - ${window.location.href} +PY - ${(new Date()).getFullYear()} +PB - National Ecological Observatory Network (NEON) +LA - en +ER - `), + generateProtoDatasetProvisionalCitation: (dataset: Record): string => { + let doiId = ''; + let version = ''; + if (dataset.doi && (dataset.doi as Record).url) { + doiId = (dataset.doi as Record).url.split('/').slice(-2).join('/'); + } + if (dataset.version) { + version = `, ${dataset.version as string}`; + } + return `TY - DATA +T1 - ${dataset.projectTitle as string}${version} (${dataset.uuid as string}) +AU - National Ecological Observatory Network (NEON) +DO - ${doiId} +UR - ${window.location.href} +AB - ${dataset.datasetAbstract as string} +PY - ${(new Date()).getFullYear()} +PB - National Ecological Observatory Network (NEON) +LA - en +ER - `; + }, + }, + ]), + + getDataProductFormats: (): CitationFormat[] => ( + DataCiteService.getCitationFormats().filter((value: CitationFormat): boolean => ( + value.applicableDownloadtypes.includes(CitationDownloadType.DATA_PRODUCT) + )) + ), + + getPrototypeDatasetFormats: (): CitationFormat[] => ( + DataCiteService.getCitationFormats().filter((value: CitationFormat): boolean => ( + value.applicableDownloadtypes.includes(CitationDownloadType.PROTOTYPE_DATASET) + )) + ), + + downloadCitation: ( + formatShortName: string, + type: CitationDownloadType, + target: Record, + doi: string, + release?: string, + ): void => { + const useProvisional: boolean = (release === 'provisional'); + const citationFormat: CitationFormat|undefined = DataCiteService.getCitationFormats() + .find((value: CitationFormat): boolean => ( + value.shortName.localeCompare(formatShortName) === 0 + )); + if (!citationFormat) { + return; + } + let fileName: string = ''; + const appliedRelease = isStringNonEmpty(release) + ? release + : 'provisional'; + switch (type) { + case CitationDownloadType.PROTOTYPE_DATASET: + fileName = `NEON-Prototype-Dataset-${target.uuid as string}.${citationFormat.extension}`; + break; + case CitationDownloadType.DATA_PRODUCT: + default: + fileName = `NEON-${target.productCode as string}-${appliedRelease}.${citationFormat.extension}`; + break; + } + if (useProvisional) { + let provCitation: string = ''; + switch (type) { + case CitationDownloadType.PROTOTYPE_DATASET: + provCitation = citationFormat.generateProtoDatasetProvisionalCitation(target); + break; + case CitationDownloadType.DATA_PRODUCT: + default: + provCitation = citationFormat.generateProvisionalCitation(target); + break; + } + if (!isStringNonEmpty(provCitation)) { + return; + } + DataCiteService.executeDownload(fileName, citationFormat.mime, provCitation); + return; + } + const citationUrl = DataCiteService.getDoiUrl(doi, citationFormat); + ajax({ + url: citationUrl, + method: 'GET', + responseType: 'text', + }).pipe( + map((citationContent: AjaxResponse) => { + DataCiteService.executeDownload(fileName, citationFormat.mime, citationContent.response); + }), + catchError((error) => { + // eslint-disable-next-line no-console + console.error(`Unable to download citation ${fileName}`, error); + return of(error); + }), + ).subscribe(); + }, + + executeDownload: (fileName: string, mimeType: string, payload: string): void => { + const link = document.createElement('a'); + if (URL) { + link.href = URL.createObjectURL(new Blob([payload], { type: mimeType })); + } else { + link.setAttribute('href', `data:${mimeType},${encodeURI(payload)}`); + } + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }, +}; + +Object.freeze(DataCiteService); + +export default DataCiteService; diff --git a/src/lib_components/service/RouteService.ts b/src/lib_components/service/RouteService.ts new file mode 100644 index 00000000..bcba4911 --- /dev/null +++ b/src/lib_components/service/RouteService.ts @@ -0,0 +1,247 @@ +import NeonEnvironment from '../components/NeonEnvironment/NeonEnvironment'; +import { isStringNonEmpty } from '../util/typeUtil'; + +/** + * Service for building routes and paths + */ +export interface IRouteService { + /** + * Gets the root web home page path + * @returns + */ + getWebHomePath: () => string; + /** + * Gets the path to the user accounts information page + * @returns + */ + getUserAccountsPath: () => string; + /** + * Gets the path to the NEON data policies information page + * @returns + */ + getDataPoliciesPath: () => string; + /** + * Gets the path to the NEON data citation policies information page + * @returns + */ + getDataPoliciesCitationPath: () => string; + /** + * Gets the path to the NEON data quality information page + * @returns + */ + getDataQualityPath: () => string; + /** + * Gets the path to the NEON news information page + * @returns + */ + getNewsPath: () => string; + /** + * Gets the path to the NEON data notifications information page + * @returns + */ + getDataNotificationsPath: () => string; + /** + * Gets the path to the NEON FAQ information page + * @returns + */ + getFaqPath: () => string; + /** + * Gets the path to the NEON download and explore information page + * @returns + */ + getDownloadExplorePath: () => string; + /** + * Gets the path to the NEON file naming conventions information page + * @returns + */ + getFileNamingConventionsPath: () => string; + /** + * Gets the path the NEON data revisions and releases information page + * @returns + */ + getDataRevisionsReleasePath: () => string; + /** + * Gets the data-samples path + * @returns + */ + getDataSamplesPath: () => string; + /** + * Gets the data-samples/data path + * @returns + */ + getDataSamplesDataPath: () => string; + /** + * Gets the samples path + * @returns + */ + getSamplesPath: () => string; + /** + * Gets the path to the data availability information page + * @returns + */ + getDataAvailabilityPath: () => string; + /** + * Gets the path to the NEONUtilities data stack in R page + * @returns + */ + getNeonUtilitiesDataStackRPath: () => string; + /** + * Gets the path to the theme detail page + * @param theme + * @returns + */ + getThemeDetailPath: (theme: string) => string; + /** + * Gets the path to the field site detail page + * @param siteCode + * @returns + */ + getFieldSiteDetailPath: (siteCode: string) => string; + /** + * Gets the path to the domain detail page + * @param domainCode + * @returns + */ + getDomainDetailPath: (domainCode: string) => string; + /** + * Gets the path to the release detail page + * @param release + * @returns + */ + getReleaseDetailPath: (release: string) => string; + + /** + * Gets the data product citation download URL + * @returns + */ + getDataProductCitationDownloadUrl: () => string; + + /** + * Gets the data api documentation path + * @returns + */ + getDataApiPath: () => string; + /** + * Gets the explore data products with with the query applied to search + * @returns + */ + getDataProductExploreSearchPath: (query: string) => string; + /** + * Gets the data product explore page path + * @returns + */ + getDataProductExplorePath: () => string; + /** + * Gets the product detail page path + * @param productCode The product code to build with + * @param release The release to build with + * @returns The full path to the page + */ + getProductDetailPath: (productCode: string, release?: string) => string; + /** + * Gets the prototype datasets page path + * @returns + */ + getPrototypeDatasetsPath: () => string; + /** + * Gets the prototype dataset detail page path + * @param uuid + * @returns + */ + getPrototypeDatasetDetailPath: (uuid: string) => string; +} + +const RouteService: IRouteService = { + getWebHomePath: (): string => NeonEnvironment.getWebHost(), + getUserAccountsPath: (): string => ( + `${NeonEnvironment.getWebHost()}/about/user-accounts` + ), + getDataPoliciesPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data/about-data/data-policies` + ), + getDataPoliciesCitationPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-policies-citation` + ), + getDataQualityPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-management/data-quality-program` + ), + getNewsPath: (): string => ( + `${NeonEnvironment.getWebHost()}/impact/newsroom/neon-news` + ), + getDataNotificationsPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-notifications` + ), + getFaqPath: (): string => ( + `${NeonEnvironment.getWebHost()}/about/faq` + ), + getDownloadExplorePath: (): string => ( + `${NeonEnvironment.getWebHost()}/resources/learning-hub/tutorials/download-explore-neon-data` + ), + getFileNamingConventionsPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-management/data-formats-conventions` + ), + getDataRevisionsReleasePath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-management/data-revisions-releases` + ), + getDataSamplesPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples` + ), + getSamplesPath: (): string => ( + `${NeonEnvironment.getWebHost()}/samples` + ), + getDataSamplesDataPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data` + ), + getDataAvailabilityPath: (): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-management/data-availability` + ), + getNeonUtilitiesDataStackRPath: (): string => ( + `${NeonEnvironment.getWebHost()}/resources/learning-hub/tutorials/neondatastackr` + ), + getThemeDetailPath: (theme: string): string => ( + `${NeonEnvironment.getWebHost()}/data/data-themes/${theme}` + ), + getFieldSiteDetailPath: (siteCode: string): string => ( + `${NeonEnvironment.getWebHost()}/field-sites/${siteCode}` + ), + getDomainDetailPath: (domainCode: string): string => ( + `${NeonEnvironment.getWebHost()}/domains/${domainCode}` + ), + getReleaseDetailPath: (release: string): string => ( + `${NeonEnvironment.getWebHost()}/data-samples/data-management/data-revisions-releases/${release}` + ), + + getDataProductCitationDownloadUrl: (): string => ( + // TODO: replace with web host once switch over happens + NeonEnvironment.getApiHost() + ), + + getDataApiPath: (): string => ( + // TODO: replace with web host once switch over happens + `${NeonEnvironment.getApiHost()}/data-api` + ), + getDataProductExploreSearchPath: (query: string): string => ( + `${RouteService.getDataProductExplorePath()}?search=${encodeURIComponent(query)}` + ), + getDataProductExplorePath: (): string => ( + // TODO: replace with web host once switch over happens + `${NeonEnvironment.getApiHost()}/data-products/explore` + ), + getProductDetailPath: (productCode: string, release?: string): string => { + const releasePath = isStringNonEmpty(release) ? `/${release}` : ''; + // TODO: replace with web host once switch over happens + return `${NeonEnvironment.getApiHost()}/data-products/${productCode}${releasePath}`; + }, + getPrototypeDatasetsPath: (): string => ( + // TODO: replace with web host once switch over happens + `${NeonEnvironment.getApiHost()}/prototype-datasets` + ), + getPrototypeDatasetDetailPath: (uuid: string): string => ( + // TODO: replace with web host once switch over happens + `${NeonEnvironment.getApiHost()}/prototype-datasets/${uuid}` + ), +}; + +Object.freeze(RouteService); + +export default RouteService; diff --git a/src/lib_components/util/__tests__/manifestUtil.js b/src/lib_components/util/__tests__/manifestUtil.js index c30ca7fd..fad68ad5 100644 --- a/src/lib_components/util/__tests__/manifestUtil.js +++ b/src/lib_components/util/__tests__/manifestUtil.js @@ -19,6 +19,7 @@ jest.mock('../../components/NeonEnvironment/NeonEnvironment', () => ({ __esModule: true, default: { getFullApiPath: jest.fn(), + getFullDownloadApiPath: jest.fn(), }, })); @@ -34,6 +35,7 @@ describe('Utils - manifestUtil', () => { beforeEach(() => { JSON.stringify.mockReset(); NeonEnvironment.getFullApiPath.mockReset(); + NeonEnvironment.getFullDownloadApiPath.mockReset(); }); describe.each([ @@ -133,15 +135,15 @@ describe('Utils - manifestUtil', () => { isError: false, }; beforeEach(() => { - NeonEnvironment.getFullApiPath.mockReturnValue('MANIFEST_REQUEST_URL'); + NeonEnvironment.getFullDownloadApiPath.mockReturnValue('MANIFEST_REQUEST_URL'); }); test('returns the rollup path if useBody is true (by default)', () => { const url = buildManifestRequestUrl(config); - expect(url).toBe('MANIFEST_REQUEST_URL/manifest/rollup'); + expect(url).toBe('MANIFEST_REQUEST_URL'); }); test('returns the built url if useBody is false', () => { const url = buildManifestRequestUrl(config, false); - const expectedUrl = 'MANIFEST_REQUEST_URL/manifest/rollup?dpcode=NEON.DOM.SITE.DPx.xxxxx.xxx&startdate=2020-01&enddate=2020-06&pkgtype=expanded&includedocs=true&sitecode=JERC&sitecode=COMO'; + const expectedUrl = 'MANIFEST_REQUEST_URL?dpcode=NEON.DOM.SITE.DPx.xxxxx.xxx&startdate=2020-01&enddate=2020-06&pkgtype=expanded&includedocs=true&sitecode=JERC&sitecode=COMO'; expect(url).toBe(expectedUrl); }); test('handles NEON.DOM.SITE already being in config', () => { @@ -150,7 +152,7 @@ describe('Utils - manifestUtil', () => { configA.productCode = 'NEON.DOM.SITE.DP0.00000.000'; const url = buildManifestRequestUrl(configA, false); - const expectedUrl = 'MANIFEST_REQUEST_URL/manifest/rollup?dpcode=NEON.DOM.SITE.DP0.00000.000&startdate=2020-01&enddate=2020-06&pkgtype=expanded&includedocs=false&sitecode=JERC&sitecode=COMO'; + const expectedUrl = 'MANIFEST_REQUEST_URL?dpcode=NEON.DOM.SITE.DP0.00000.000&startdate=2020-01&enddate=2020-06&pkgtype=expanded&includedocs=false&sitecode=JERC&sitecode=COMO'; expect(url).toBe(expectedUrl); }); }); diff --git a/src/lib_components/util/liferayNotificationsUtil.js b/src/lib_components/util/liferayNotificationsUtil.js index 6f44d3f0..3468d5e6 100644 --- a/src/lib_components/util/liferayNotificationsUtil.js +++ b/src/lib_components/util/liferayNotificationsUtil.js @@ -1,15 +1,12 @@ +import NeonEnvironment from '../components/NeonEnvironment'; + // NOTE: This is not defined in NeonEnvironment, where one would expect such // things, because this whole component is temporary. When Liferay is dead and // React pages can pull notifications from its replacement (Drupal), then this // should be appropriately refactored and hardened. -export const getLiferayNotificationsApiPath = () => { - let base = window.location.origin; - // Override localhost dev - if (base.includes('localhost')) { - base = 'https://local-data.neonscience.org'; - } - return `${base}/auth0/liferaynotifications`; -}; +export const getLiferayNotificationsApiPath = () => ( + NeonEnvironment.getFullAuthPath('notifications') +); // Non-secure string hashing function found here: https://stackoverflow.com/a/8831937 // Use for unique id for notifications for keying nodes and tracking dismissal cookies diff --git a/src/lib_components/util/manifestUtil.ts b/src/lib_components/util/manifestUtil.ts index 727e5a61..93b00566 100644 --- a/src/lib_components/util/manifestUtil.ts +++ b/src/lib_components/util/manifestUtil.ts @@ -62,7 +62,7 @@ export const buildManifestRequestUrl = (config: ManifestConfig, useBody = true): packageType, documentation, } = config; - let url = `${NeonEnvironment.getFullApiPath('manifest')}/manifest/rollup`; + let url = NeonEnvironment.getFullDownloadApiPath('manifestRollup'); if (!useBody) { const siteCodesParam = buildSiteCodesParams(sites); const productCodeParam = productCode.startsWith('NEON.DOM.SITE') @@ -124,7 +124,7 @@ export const buildS3FilesRequestUrl = ( export const downloadManifest = (manifest: ManifestRequest) => { const form = document.createElement('form'); form.style.display = 'none'; - form.action = `${NeonEnvironment.getFullApiPath('download')}/stream`; + form.action = NeonEnvironment.getFullDownloadApiPath('downloadStream'); form.method = 'POST'; const input = document.createElement('input'); @@ -203,9 +203,9 @@ export const formatBytes = (bytes: number) => { export const getSizeEstimateFromManifestResponse = (response: any) => { if (typeof response !== 'object' || response === null - || typeof response.data !== 'object' || response.data === null - || !Array.isArray(response.data.manifestEntries) - || !response.data.manifestEntries.length) { + || typeof response.data !== 'object' || response.data === null + || !Array.isArray(response.data.manifestEntries) + || !response.data.manifestEntries.length) { return 0; } return response.data.manifestEntries.reduce((total: number, entry: any) => ( @@ -215,9 +215,9 @@ export const getSizeEstimateFromManifestResponse = (response: any) => { export const getSizeEstimateFromManifestRollupResponse = (response: any) => { if (typeof response !== 'object' || response === null - || typeof response.data !== 'object' || response.data === null - || typeof response.data.totalBytes !== 'number' - || response.data.totalBytes === null) { + || typeof response.data !== 'object' || response.data === null + || typeof response.data.totalBytes !== 'number' + || response.data.totalBytes === null) { return 0; } return response.data.totalBytes; diff --git a/tsconfig.d.json b/tsconfig.d.json index daf197ae..72bedea1 100644 --- a/tsconfig.d.json +++ b/tsconfig.d.json @@ -10,6 +10,7 @@ "include": [ "./src/lib_components/components/**/*", "./src/lib_components/flow/**/*", + "./src/lib_components/service/**/*", "./src/lib_components/types/**/*", "./src/lib_components/util/**/*", "./src/lib_components/*.js", diff --git a/tsconfig.json b/tsconfig.json index 05a2f792..ad3b2717 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,7 @@ "noImplicitAny": true, "resolveJsonModule": true, "noEmit": true, - "jsx": "react", + "jsx": "react-jsx", "allowJs": true, "isolatedModules": true, "noFallthroughCasesInSwitch": true