Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/deploying/deploying-terriamap.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ And on the server, change to the directory where you copied those files and dire

The server will start on port 3001. You can specify a different port by adding `--port 1234` to the command-line above.

Ensure that you specify the `baseHref` path in your `devserverconfig.json` if you are serving your TerriaMap from a directory.

It is usually a good idea to run another web server, such as [nginx](https://nginx.org/en/) or [Varnish](https://varnish-cache.org/) on port 80 and then reverse-proxy to the Node.js server, rather than running terriajs-server on port 80 directly. You will find a varnish VCL file with the TerriaMap source code in the [deploy/varnish directory](https://github.com/TerriaJS/TerriaMap/tree/master/deploy/varnish). In addition to acting as a reverse proxy for the Node.js server, the supplied Varnish configuration also caches requests to proxied map data in order to improve performance.

### Using any web server
Expand All @@ -38,6 +40,7 @@ It is usually a good idea to run another web server, such as [nginx](https://ngi
2. It includes a simple service at `/proxy` that allows TerriaJS to access geospatial data servers that don't support [CORS](../connecting-to-data/cross-origin-resource-sharing.md). If this service is not available, TerriaJS won't be able to access any datasets that are on other servers and that don't support CORS.
3. It includes another service at `/convert` that uses [GDAL](http://www.gdal.org/) and OGR to transform otherwise unsupported geospatial vector data (e.g. shapefiles) to GeoJSON for display by the TerriaJS client. If this service is not available, these data formats will not be supported. However, all the [formats that TerriaJS supports directly](../connecting-to-data/catalog-items.md) will work just fine.
* When configured correctly, it persists blobs of JSON for use in the sharing feature. If this service is not available, the JSON can be stored in the share URL, instead. However, this makes for some extremely long URLs.
4. It reroutes and serves up a build-time-prerendered index.html of your catalog URLs so they can be indexed by search engines.

If these limitations are acceptable, you can run your TerriaMap on virtually any web server by simply copying the TerriaMap `wwwroot` onto the server!

Expand Down
9 changes: 9 additions & 0 deletions lib/ReactViewModels/TerriaRouting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Route paths for the app.

var CATALOG_ROUTE = "/catalog/";
var CATALOG_MEMBER_ROUTE = `${CATALOG_ROUTE}:catalogMemberId`;

module.exports = {
CATALOG_ROUTE,
CATALOG_MEMBER_ROUTE
};
23 changes: 20 additions & 3 deletions lib/ReactViewModels/ViewState.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import DisclaimerHandler from "./DisclaimerHandler";
import getAncestors from "../Models/getAncestors";
import addedByUser from "../Core/addedByUser";
import knockout from "terriajs-cesium/Source/ThirdParty/knockout";
import { CATALOG_ROUTE, CATALOG_MEMBER_ROUTE } from "./TerriaRouting";
import MouseCoords from "./MouseCoords";
import SearchState from "./SearchState";

Expand Down Expand Up @@ -39,14 +40,14 @@ export default class ViewState {
this.terria = terria;
this.previewedItem = undefined;
this.userDataPreviewedItem = undefined;
this.explorerPanelIsVisible = false;
this.shareModalIsVisible = false;
this.activeTabCategory = DATA_CATALOG_NAME;
this.activeTabSubCategory = null; // Used to refer to an individual data-catalog tab
this.isDraggingDroppingFile = false;
this.mobileView = null;
this.isMapFullScreen = false;
this.myDataIsUploadView = true;
this.history = {};

/**
* Gets or sets a value indicating whether the small screen (mobile) user interface should be used.
Expand Down Expand Up @@ -107,10 +108,12 @@ export default class ViewState {

this.featurePrompts = [];

this._explorerPanelIsVisible = false;

knockout.track(this, [
"previewedItem",
"catalogSearch",
"explorerPanelIsVisible",
"_explorerPanelIsVisible",
"shareModalIsVisible",
"activeTabCategory",
"activeTabIdInCategory",
Expand All @@ -135,6 +138,20 @@ export default class ViewState {
"featurePrompts"
]);

knockout.defineProperty(this, "explorerPanelIsVisible", {
get: function() {
return this._explorerPanelIsVisible;
},
set: function(bool) {
if (!bool && this.location && this.location.pathname !== "/") {
setTimeout(() => {
this.history.push("/");
}, 300);
}
this._explorerPanelIsVisible = bool;
}
});

knockout.defineProperty(this, "chartIsOpen", {
get: function() {
const chartableItems = this.terria.catalog.chartableItems;
Expand Down Expand Up @@ -174,7 +191,6 @@ export default class ViewState {
});

// Reflect preview id from terria when loaded from an init source

this._sharedFromExplorerPanelSubscription = knockout
.getObservable(terria, "sharedFromExplorerPanel")
.subscribe(sharedFromExplorerPanel => {
Expand Down Expand Up @@ -265,6 +281,7 @@ export default class ViewState {
}

dispose() {
this._explorerPanelIsVisibleSubscription.dispose();
this._sharedFromExplorerPanelSubscription.dispose();
this._previewedItemIdSubscription.dispose();
this._pickedFeaturesSubscription.dispose();
Expand Down
8 changes: 5 additions & 3 deletions lib/ReactViews/DataCatalog/CatalogGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
import classNames from "classnames";

Expand All @@ -15,8 +16,8 @@ import Styles from "./data-catalog-group.scss";
function CatalogGroup(props) {
return (
<li className={Styles.root}>
<button
type="button"
<Link
to={props.linkTo}
className={classNames(
Styles.btnCatalog,
{ [Styles.btnCatalogTopLevel]: props.topLevel },
Expand Down Expand Up @@ -47,7 +48,7 @@ function CatalogGroup(props) {
<Icon glyph={Icon.GLYPHS.closed} />
)}
</span>
</button>
</Link>
<If condition={props.removable}>
<button
type="button"
Expand Down Expand Up @@ -89,6 +90,7 @@ function CatalogGroup(props) {
CatalogGroup.propTypes = {
text: PropTypes.string,
title: PropTypes.string,
linkTo: PropTypes.string,
topLevel: PropTypes.bool,
open: PropTypes.bool,
loading: PropTypes.bool,
Expand Down
9 changes: 5 additions & 4 deletions lib/ReactViews/DataCatalog/CatalogItem.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
import classNames from "classnames";
import Icon from "../Icon.jsx";

import defaultValue from "terriajs-cesium/Source/Core/defaultValue";

import Styles from "./data-catalog-item.scss";
Expand All @@ -28,16 +28,16 @@ function CatalogItem(props) {
const stateToTitle = defaultValue(props.titleOverrides, STATE_TO_TITLE);
return (
<li className={classNames(Styles.root)}>
<button
type="button"
<Link
to={props.linkTo}
onClick={props.onTextClick}
title={props.title}
className={classNames(Styles.btnCatalogItem, {
[Styles.btnCatalogItemIsPreviewed]: props.selected
})}
>
{props.text}
</button>
</Link>
<button
type="button"
onClick={props.onBtnClick}
Expand All @@ -55,6 +55,7 @@ CatalogItem.propTypes = {
selected: PropTypes.bool,
text: PropTypes.string,
title: PropTypes.string,
linkTo: PropTypes.string,
onBtnClick: PropTypes.func,
btnState: PropTypes.oneOf(Object.keys(STATE_TO_ICONS)),
titleOverrides: PropTypes.object
Expand Down
2 changes: 2 additions & 0 deletions lib/ReactViews/DataCatalog/DataCatalogGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import createReactClass from "create-react-class";
import PropTypes from "prop-types";
import URI from "urijs";
import addedByUser from "../../Core/addedByUser";
import removeUserAddedData from "../../Models/removeUserAddedData";
import CatalogGroup from "./CatalogGroup";
Expand Down Expand Up @@ -90,6 +91,7 @@ const DataCatalogGroup = createReactClass({

return (
<CatalogGroup
linkTo={URI.encode(group.uniqueId)}
text={this.getNameOrPrettyUrl()}
title={getAncestors(group)
.map(member => member.nameInCatalog)
Expand Down
13 changes: 9 additions & 4 deletions lib/ReactViews/DataCatalog/DataCatalogItem.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from "react";
import createReactClass from "create-react-class";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
import defined from "terriajs-cesium/Source/Core/defined";
import addedByUser from "../../Core/addedByUser";
import removeUserAddedData from "../../Models/removeUserAddedData";
import CatalogItem from "./CatalogItem";
import getAncestors from "../../Models/getAncestors";
import ObserveModelMixin from "../ObserveModelMixin";
import raiseErrorOnRejectedPromise from "../../Models/raiseErrorOnRejectedPromise";
import URI from "urijs";

const STATE_TO_TITLE = {
loading: "Loading...",
Expand All @@ -23,6 +25,7 @@ const DataCatalogItem = createReactClass({

propTypes: {
item: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
viewState: PropTypes.object.isRequired,
removable: PropTypes.bool,
terria: PropTypes.object
Expand Down Expand Up @@ -73,9 +76,10 @@ const DataCatalogItem = createReactClass({
},

isSelected() {
return addedByUser(this.props.item)
? this.props.viewState.userDataPreviewedItem === this.props.item
: this.props.viewState.previewedItem === this.props.item;
return (
this.props.item.uniqueId ===
URI.decode(this.props.match.params.catalogMemberId)
);
},

render() {
Expand All @@ -84,6 +88,7 @@ const DataCatalogItem = createReactClass({
<CatalogItem
onTextClick={this.setPreviewedItem}
selected={this.isSelected()}
linkTo={URI.encode(item.uniqueId)}
text={item.nameInCatalog}
title={getAncestors(item)
.map(member => member.nameInCatalog)
Expand Down Expand Up @@ -114,4 +119,4 @@ const DataCatalogItem = createReactClass({
}
});

module.exports = DataCatalogItem;
module.exports = withRouter(DataCatalogItem);
2 changes: 2 additions & 0 deletions lib/ReactViews/DataCatalog/data-catalog-group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
composes: btn from "../../Sass/common/_buttons.scss";
@extend %wrap;

display: block;
color: $text-black;
text-align: left;
font-size: $font-size-small;
padding: 8px 30px + $padding;
Expand Down
2 changes: 2 additions & 0 deletions lib/ReactViews/DataCatalog/data-catalog-item.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
}

.btn-catalog-item {
display: block;
color: $text-black;
font-size: $font-size-small;
composes: btn from "../../Sass/common/_buttons.scss";
@extend %wrap;
Expand Down
47 changes: 47 additions & 0 deletions lib/ReactViews/ErrorBoundary/ErrorBoundary.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import PropTypes from "prop-types";
import raiseErrorToUser from "../../Models/raiseErrorToUser";

// https://reactjs.org/docs/error-boundaries.html
export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error, info) {
const children = this.props.children;
const name =
(children && children.type && children.type.displayName) ||
children.type.name ||
"Unnamed Component";
const errorString = (error.toString && error.toString()) || error;

this.props.terria.analytics.logEvent(
"error",
"boundary",
name,
errorString
);
raiseErrorToUser(this.props.terria, error);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}

return this.props.children;
}
}

ErrorBoundary.propTypes = {
terria: PropTypes.object.isRequired,
children: PropTypes.node.isRequired
};
Loading