) =>
+ parameter.setValue(CommonStrata.user, e.target.value),
+ [parameter]
+ );
+
+ return (
+
+
+
+ );
+ });
+
+export default DateTimeParameterEditor;
diff --git a/lib/ReactViews/Analytics/InvokeFunction.jsx b/lib/ReactViews/Analytics/InvokeFunction.jsx
index b58172ff7ec..2b9d06dee52 100644
--- a/lib/ReactViews/Analytics/InvokeFunction.jsx
+++ b/lib/ReactViews/Analytics/InvokeFunction.jsx
@@ -117,12 +117,10 @@ class InvokeFunction extends React.Component {
return ;
}
- let invalidParameters = false;
- if (defined(this.props.previewed.parameters)) {
- invalidParameters = !this.props.previewed.functionParameters.every(
- this.validateParameter.bind(this)
- );
- }
+ const invalidParameters = this.props.previewed.functionParameters.some(
+ (param) => this.validateParameter(param) !== true
+ );
+
const { t } = this.props;
return (
diff --git a/lib/ReactViews/Analytics/ParameterEditor.jsx b/lib/ReactViews/Analytics/ParameterEditor.jsx
index ba9e9067c51..2b9668bbe58 100644
--- a/lib/ReactViews/Analytics/ParameterEditor.jsx
+++ b/lib/ReactViews/Analytics/ParameterEditor.jsx
@@ -9,6 +9,7 @@ import PropTypes from "prop-types";
import PointParameterEditor from "./PointParameterEditor";
import LineParameterEditor from "./LineParameterEditor";
import PolygonParameterEditor from "./PolygonParameterEditor";
+import RectangleParameterEditor from "./RectangleParameterEditor";
import RegionParameterEditor from "./RegionParameterEditor";
import RegionTypeParameterEditor from "./RegionTypeParameterEditor";
import BooleanParameterEditor from "./BooleanParameterEditor";
@@ -142,27 +143,27 @@ ParameterEditor.parameterTypeConverters = [
}
}
},
- // {
- // id: "rectangle",
- // parameterTypeToDiv: function RectangleParameterToDiv(
- // type,
- // parameterEditor
- // ) {
- // if (type === this.id) {
- // return (
- //
- // {parameterEditor.renderLabel()}
- //
- //
- // );
- // }
- // }
- // },
+ {
+ id: "rectangle",
+ parameterTypeToDiv: function RectangleParameterToDiv(
+ type,
+ parameterEditor
+ ) {
+ if (type === this.id) {
+ return (
+
+ {parameterEditor.renderLabel()}
+
+
+ );
+ }
+ }
+ },
{
id: "polygon",
parameterTypeToDiv: function PolygonParameterToDiv(type, parameterEditor) {
diff --git a/lib/ReactViews/Analytics/RectangleParameterEditor.jsx b/lib/ReactViews/Analytics/RectangleParameterEditor.jsx
new file mode 100644
index 00000000000..578b57b18cd
--- /dev/null
+++ b/lib/ReactViews/Analytics/RectangleParameterEditor.jsx
@@ -0,0 +1,125 @@
+"use strict";
+
+import React from "react";
+
+import PropTypes from "prop-types";
+
+import defined from "terriajs-cesium/Source/Core/defined";
+
+import Styles from "./parameter-editors.scss";
+
+import CesiumMath from "terriajs-cesium/Source/Core/Math";
+import Cartographic from "terriajs-cesium/Source/Core/Cartographic";
+import Ellipsoid from "terriajs-cesium/Source/Core/Ellipsoid";
+import UserDrawing from "../../Models/UserDrawing";
+import { withTranslation } from "react-i18next";
+import { observer } from "mobx-react";
+import { runInAction } from "mobx";
+import CommonStrata from "../../Models/Definition/CommonStrata";
+
+@observer
+class RectangleParameterEditor extends React.Component {
+ static propTypes = {
+ previewed: PropTypes.object,
+ parameter: PropTypes.object,
+ viewState: PropTypes.object,
+ t: PropTypes.func.isRequired
+ };
+
+ setValueFromText(e) {
+ RectangleParameterEditor.setValueFromText(e, this.props.parameter);
+ }
+
+ selectPolygonOnMap() {
+ selectOnMap(
+ this.props.previewed.terria,
+ this.props.viewState,
+ this.props.parameter
+ );
+ }
+
+ render() {
+ const { t } = this.props;
+ return (
+
+
+
+ {t("analytics.clickToDrawRectangle")}
+
+
+ );
+ }
+}
+
+/**
+ * Triggered when user types value directly into field.
+ * @param {String} e Text that user has entered manually.
+ * @param {FunctionParameter} parameter Parameter to set value on.
+ */
+RectangleParameterEditor.setValueFromText = function (e, parameter) {
+ parameter.setValue(CommonStrata.user, [JSON.parse(e.target.value)]);
+};
+
+/**
+ * Given a value, return it in human readable form for display.
+ * @param {Object} value Native format of parameter value.
+ * @return {String} String for display
+ */
+export function getDisplayValue(value) {
+ if (!defined(value)) {
+ return "";
+ }
+ return `${value.east}, ${value.north}, ${value.west}, ${value.south}`;
+}
+
+/**
+ * Prompt user to select/draw on map in order to define parameter.
+ * @param {Terria} terria Terria instance.
+ * @param {Object} viewState ViewState.
+ * @param {FunctionParameter} parameter Parameter.
+ */
+export function selectOnMap(terria, viewState, parameter) {
+ const userDrawing = new UserDrawing({
+ terria: terria,
+ drawRectangle: true,
+ onCleanUp: function () {
+ viewState.openAddData();
+ },
+ onDrawingComplete: function (params) {
+ if (params.points) {
+ const cartographicPoints = params.points.map((point) => {
+ const cartographic = Cartographic.fromCartesian(
+ point,
+ Ellipsoid.WGS84
+ );
+ return {
+ latitude: CesiumMath.toDegrees(cartographic.latitude),
+ longitude: CesiumMath.toDegrees(cartographic.longitude)
+ };
+ });
+ const rectangle = {
+ west: cartographicPoints[0].longitude,
+ south: cartographicPoints[0].latitude,
+ east: cartographicPoints[1].longitude,
+ north: cartographicPoints[1].latitude
+ };
+ runInAction(() => {
+ parameter.setValue(CommonStrata.user, rectangle);
+ });
+ }
+ }
+ });
+
+ userDrawing.enterDrawMode();
+}
+
+export default withTranslation()(RectangleParameterEditor);
diff --git a/lib/ReactViews/Analytics/RegionDataParameterEditor.jsx b/lib/ReactViews/Analytics/RegionDataParameterEditor.jsx
index ff35de5c814..ac3851207c5 100644
--- a/lib/ReactViews/Analytics/RegionDataParameterEditor.jsx
+++ b/lib/ReactViews/Analytics/RegionDataParameterEditor.jsx
@@ -7,7 +7,7 @@ import PropTypes from "prop-types";
import defined from "terriajs-cesium/Source/Core/defined";
import knockout from "terriajs-cesium/Source/ThirdParty/knockout";
import VarType from "../../Map/VarType";
-import CatalogItem from "../DataCatalog/CatalogItem";
+import CatalogItem, { ButtonState } from "../DataCatalog/CatalogItem";
import CatalogGroup from "../DataCatalog/CatalogGroup";
import Styles from "./parameter-editors.scss";
@@ -238,7 +238,11 @@ const RegionDataParameterEditor = createReactClass({
selected={this.isActive(catalogItem, column)}
text={column.name}
onBtnClick={this.toggleActive.bind(this, catalogItem, column)}
- btnState={this.isActive(catalogItem, column) ? "remove" : "add"}
+ btnState={
+ this.isActive(catalogItem, column)
+ ? ButtonState.Remove
+ : ButtonState.Add
+ }
/>
);
}
diff --git a/lib/ReactViews/Analytics/parameter-editors.scss b/lib/ReactViews/Analytics/parameter-editors.scss
index aaacf5c06cc..8265df2bf9c 100644
--- a/lib/ReactViews/Analytics/parameter-editors.scss
+++ b/lib/ReactViews/Analytics/parameter-editors.scss
@@ -64,6 +64,11 @@
margin-bottom: $padding;
position: relative;
clear: both;
+
+ input[type="datetime-local"] {
+ width: 50%;
+ }
+
input[type="date"] {
width: 50%;
float: left;
diff --git a/lib/ReactViews/BottomDock/Timeline/DateFormats.js b/lib/ReactViews/BottomDock/Timeline/DateFormats.ts
similarity index 53%
rename from lib/ReactViews/BottomDock/Timeline/DateFormats.js
rename to lib/ReactViews/BottomDock/Timeline/DateFormats.ts
index a8558cf95d4..0026ddc799d 100644
--- a/lib/ReactViews/BottomDock/Timeline/DateFormats.js
+++ b/lib/ReactViews/BottomDock/Timeline/DateFormats.ts
@@ -1,15 +1,13 @@
-"use strict";
-
import defined from "terriajs-cesium/Source/Core/defined";
/**
* Formats a date according to the locale if provided, otherwise in a dd/mm/yyyy format.
*
- * @param {Date} d the date to format
- * @param {Locale} [locale] the locale to use for formatting
- * @returns {string} A formatted date.
+ * @param d the date to format
+ * @param locale the locale to use for formatting
+ * @returns A formatted date.
*/
-export function formatDate(d, locale) {
+export function formatDate(d: Date, locale?: string): string {
if (defined(locale)) {
return d.toLocaleDateString(locale);
}
@@ -19,11 +17,11 @@ export function formatDate(d, locale) {
/**
* Formats the time according to the locale if provided, otherwise in a hh:mm:ss format.
*
- * @param {Date} d the date to format
- * @param {Locale} [locale] the locale to use for formatting
- * @returns {string} A formatted time.
+ * @param d the date to format
+ * @param locale the locale to use for formatting
+ * @returns A formatted time.
*/
-export function formatTime(d, locale) {
+export function formatTime(d: Date, locale?: string): string {
if (defined(locale)) {
return d.toLocaleTimeString(locale);
}
@@ -35,20 +33,20 @@ export function formatTime(d, locale) {
/**
* Combines {@link #formatDate} and {@link #formatTime}.
*
- * @param {Date} d the date to format
- * @param {Locale} [locale] the locale to use for formatting
- * @returns {string} A formatted date and time with a comma separating them.
+ * @param d the date to format
+ * @param locale the locale to use for formatting
+ * @returns A formatted date and time with a comma separating them.
*/
-export function formatDateTime(d, locale) {
+export function formatDateTime(d: Date, locale?: string): string {
return formatDate(d, locale) + ", " + formatTime(d, locale);
}
/**
* Puts a leading 0 in front of a number of it's less than 10.
*
- * @param {number} s A number to pad
- * @returns {string} A string representing a two-digit number.
+ * @param s A number to pad
+ * @returns A string representing a two-digit number.
*/
-function pad(s) {
+function pad(s: number): string {
return s < 10 ? "0" + s : `${s}`;
}
diff --git a/lib/ReactViews/BottomDock/Timeline/Timeline.d.ts b/lib/ReactViews/BottomDock/Timeline/Timeline.d.ts
new file mode 100644
index 00000000000..8cd8b6c80c0
--- /dev/null
+++ b/lib/ReactViews/BottomDock/Timeline/Timeline.d.ts
@@ -0,0 +1,13 @@
+import React from "react";
+import IElementConfig from "../../../Models/IElementConfig";
+import Terria from "../../../Models/Terria";
+
+interface PropsType {
+ terria: Terria;
+ locale?: unknown;
+ elementConfig?: IElementConfig;
+}
+
+declare class Timeline extends React.Component
{}
+
+export default Timeline;
diff --git a/lib/ReactViews/Clipboard.tsx b/lib/ReactViews/Clipboard.tsx
index 19306f063d1..a9f0f60fdd9 100644
--- a/lib/ReactViews/Clipboard.tsx
+++ b/lib/ReactViews/Clipboard.tsx
@@ -58,6 +58,7 @@ const Clipboard: React.FC = (props) => {
removeTimeout();
clipboardBtn.destroy();
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [id]);
const isLightTheme = theme === "light";
diff --git a/lib/ReactViews/Custom/ApiTableCustomComponent.ts b/lib/ReactViews/Custom/ApiTableCustomComponent.ts
index 816648404f6..20e679d9211 100644
--- a/lib/ReactViews/Custom/ApiTableCustomComponent.ts
+++ b/lib/ReactViews/Custom/ApiTableCustomComponent.ts
@@ -26,7 +26,7 @@ export default class ApiTableChartCustomComponent extends ChartCustomComponent {}
+
+export default ChartPanel;
diff --git a/lib/ReactViews/Custom/Chart/ZoomX.jsx b/lib/ReactViews/Custom/Chart/ZoomX.jsx
index f2eef609237..b3bd31ff5cd 100644
--- a/lib/ReactViews/Custom/Chart/ZoomX.jsx
+++ b/lib/ReactViews/Custom/Chart/ZoomX.jsx
@@ -1,6 +1,6 @@
import { observer } from "mobx-react";
import { zoom as d3Zoom } from "d3-zoom";
-import { select as d3Select, event as d3Event } from "d3-selection";
+import { select as d3Select } from "d3-selection";
import PropTypes from "prop-types";
import React from "react";
@@ -20,9 +20,9 @@ class ZoomX extends React.Component {
this.zoom = d3Zoom()
.scaleExtent(props.scaleExtent)
.translateExtent(props.translateExtent)
- .on("zoom", () =>
- props.onZoom(d3Event.transform.rescaleX(this.props.initialScale))
- );
+ .on("zoom", (event) => {
+ props.onZoom(event.transform.rescaleX(this.props.initialScale));
+ });
}
componentDidMount() {
diff --git a/lib/ReactViews/Custom/FeedbackLinkCustomComponent.tsx b/lib/ReactViews/Custom/FeedbackLinkCustomComponent.tsx
index 8fb74270d6b..173d820e996 100644
--- a/lib/ReactViews/Custom/FeedbackLinkCustomComponent.tsx
+++ b/lib/ReactViews/Custom/FeedbackLinkCustomComponent.tsx
@@ -71,7 +71,7 @@ export default class FeedbackLinkCustomComponent extends CustomComponent {
processNode(
context: ProcessNodeContext,
node: DomElement,
- children: ReactElement[]
+ _children: ReactElement[]
) {
if (!context.viewState) return undefined;
diff --git a/lib/ReactViews/Custom/SOSChartCustomComponent.ts b/lib/ReactViews/Custom/SOSChartCustomComponent.ts
index 22d5de61051..b73f75eba67 100644
--- a/lib/ReactViews/Custom/SOSChartCustomComponent.ts
+++ b/lib/ReactViews/Custom/SOSChartCustomComponent.ts
@@ -22,9 +22,9 @@ export default class SOSChartCustomComponent extends ChartCustomComponent
this.createItemReference(
context.catalogItem as SensorObservationServiceCatalogItem
@@ -43,7 +43,7 @@ export default class SOSChartCustomComponent extends ChartCustomComponent terria.configParameters.cesiumIonOAuth2ApplicationID !== undefined,
+ () => {
+ addOrReplaceRemoteFileUploadType("cesium-ion", {
+ value: "cesium-ion",
+ name: "core.dataType.cesium-ion",
+ customComponent: CesiumIonConnector
+ });
+ }
+ );
+ }
}
diff --git a/lib/ReactViews/Disclaimer.d.ts b/lib/ReactViews/Disclaimer.d.ts
new file mode 100644
index 00000000000..7c6ae10693c
--- /dev/null
+++ b/lib/ReactViews/Disclaimer.d.ts
@@ -0,0 +1,5 @@
+import React from "react";
+
+declare class Disclaimer extends React.Component<{}> {}
+
+export default Disclaimer;
diff --git a/lib/ReactViews/DragDropNotification.d.ts b/lib/ReactViews/DragDropNotification.d.ts
new file mode 100644
index 00000000000..33b2a353455
--- /dev/null
+++ b/lib/ReactViews/DragDropNotification.d.ts
@@ -0,0 +1,5 @@
+import React from "react";
+
+declare class DragDropNotification extends React.Component<{}> {}
+
+export default DragDropNotification;
diff --git a/lib/ReactViews/DragDropNotification.jsx b/lib/ReactViews/DragDropNotification.jsx
index 63bf30c8c7d..5edcf1a9cfb 100644
--- a/lib/ReactViews/DragDropNotification.jsx
+++ b/lib/ReactViews/DragDropNotification.jsx
@@ -1,4 +1,3 @@
-"use strict";
import classNames from "classnames";
import { reaction } from "mobx";
import { observer } from "mobx-react";
diff --git a/lib/ReactViews/Errors/RaiseToUserErrorBoundary.tsx b/lib/ReactViews/Errors/RaiseToUserErrorBoundary.tsx
index 595f8a9febc..f7fc07c9381 100644
--- a/lib/ReactViews/Errors/RaiseToUserErrorBoundary.tsx
+++ b/lib/ReactViews/Errors/RaiseToUserErrorBoundary.tsx
@@ -6,6 +6,7 @@ type PropsType = {
viewState: ViewState;
// Pass in options to customize the title and other presentation aspects of the error
terriaErrorOptions?: TerriaErrorOverrides;
+ children?: React.ReactNode;
};
/**
@@ -14,13 +15,13 @@ type PropsType = {
export default class RaiseToUserErrorBoundary extends React.Component {
state = { hasError: false };
- static getDerivedStateFromError(error: any) {
+ static getDerivedStateFromError(_error: Error) {
return {
hasError: true
};
}
- componentDidCatch(error: Error, errorInfo: ErrorInfo) {
+ componentDidCatch(error: Error, _errorInfo: ErrorInfo) {
this.props.viewState.terria.raiseErrorToUser(
error,
this.props.terriaErrorOptions
diff --git a/lib/ReactViews/ExplorerWindow/ModalPopup.tsx b/lib/ReactViews/ExplorerWindow/ModalPopup.tsx
index 2f5e991d476..1f05b8117f8 100644
--- a/lib/ReactViews/ExplorerWindow/ModalPopup.tsx
+++ b/lib/ReactViews/ExplorerWindow/ModalPopup.tsx
@@ -50,6 +50,7 @@ const ModalPopup: React.FC = (props) => {
} else {
slideOut();
}
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.isVisible]);
useEffect(() => {
diff --git a/lib/ReactViews/ExplorerWindow/Tabs.d.ts b/lib/ReactViews/ExplorerWindow/Tabs.d.ts
new file mode 100644
index 00000000000..8714b383e1c
--- /dev/null
+++ b/lib/ReactViews/ExplorerWindow/Tabs.d.ts
@@ -0,0 +1,13 @@
+import React from "react";
+import Terria from "../../Models/Terria";
+import ViewState from "../../ReactViewModels/ViewState";
+
+interface PropsType {
+ terria: Terria;
+ viewState: ViewState;
+ tabs?: unknown[];
+}
+
+declare class Tabs extends React.Component {}
+
+export default Tabs;
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/AddData.jsx b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/AddData.jsx
index 6998dd16595..bd9d73ce2fc 100644
--- a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/AddData.jsx
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/AddData.jsx
@@ -1,4 +1,5 @@
-import createReactClass from "create-react-class";
+import { observer } from "mobx-react";
+import { runInAction } from "mobx";
import PropTypes from "prop-types";
import React from "react";
import { Trans, withTranslation } from "react-i18next";
@@ -26,10 +27,9 @@ import TerriaError from "../../../../Core/TerriaError";
/**
* Add data panel in modal window -> My data tab
*/
-const AddData = createReactClass({
- displayName: "AddData",
-
- propTypes: {
+@observer
+class AddData extends React.Component {
+ static propTypes = {
terria: PropTypes.object,
viewState: PropTypes.object,
resetTab: PropTypes.func,
@@ -42,9 +42,11 @@ const AddData = createReactClass({
onFileAddFinished: PropTypes.func.isRequired,
onUrlAddFinished: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
- },
+ };
+
+ constructor(props) {
+ super(props);
- getInitialState() {
const remoteDataTypes =
this.props.remoteDataTypes ?? getDataType().remoteDataType;
@@ -58,27 +60,26 @@ const AddData = createReactClass({
return { ...dataType, name: `${dataType.name}${extensions}` };
});
- return {
+ this.state = {
remoteDataTypes,
localDataTypes,
- remoteDataType: remoteDataTypes[0], // By default select the first item (auto)
localDataType: localDataTypes[0],
remoteUrl: "", // By default there's no remote url
isLoading: false
};
- },
+ }
selectLocalOption(option) {
this.setState({
localDataType: option
});
- },
+ }
selectRemoteOption(option) {
- this.setState({
- remoteDataType: option
+ runInAction(() => {
+ this.props.viewState.remoteDataType = option;
});
- },
+ }
handleUploadFile(e) {
this.setState({
@@ -99,7 +100,7 @@ const AddData = createReactClass({
// reset active tab when file handling is done
this.props.resetTab();
});
- },
+ }
async handleUrl(e) {
const url = this.state.remoteUrl;
@@ -113,14 +114,17 @@ const AddData = createReactClass({
isLoading: true
});
let promise;
- if (this.state.remoteDataType.value === "auto") {
+ if (
+ !this.props.viewState.remoteDataType ||
+ this.props.viewState.remoteDataType.value === "auto"
+ ) {
promise = createCatalogItemFromFileOrUrl(
this.props.terria,
this.props.viewState,
this.state.remoteUrl,
- this.state.remoteDataType.value
+ this.props.viewState.remoteDataType?.value
);
- } else if (this.state.remoteDataType.value === "json") {
+ } else if (this.props.viewState.remoteDataType.value === "json") {
promise = loadJson(this.state.remoteUrl)
.then((data) => {
if (data.error) {
@@ -151,7 +155,7 @@ const AddData = createReactClass({
this.props.terria,
"",
CommonStrata.defaults,
- { type: this.state.remoteDataType.value, name: url },
+ { type: this.props.viewState.remoteDataType.value, name: url },
{}
).throwIfUndefined({
message: `An error occurred trying to add data from URL: ${url}`
@@ -183,13 +187,13 @@ const AddData = createReactClass({
});
this.props.resetTab();
});
- },
+ }
onRemoteUrlChange(event) {
this.setState({
remoteUrl: event.target.value
});
- },
+ }
renderPanels() {
const { t } = this.props;
@@ -214,6 +218,9 @@ const AddData = createReactClass({
},
[]);
+ const remoteDataType =
+ this.props.viewState.remoteDataType ?? this.state.remoteDataTypes[0];
+
return (
{this.props.activeTab === "local" && (
@@ -228,7 +235,7 @@ const AddData = createReactClass({
@@ -244,7 +251,7 @@ const AddData = createReactClass({
{this.state.isLoading && }
@@ -261,51 +268,65 @@ const AddData = createReactClass({
- {this.state.remoteDataType?.description
+ {remoteDataType?.description
? parseCustomMarkdownToReactWithOptions(
- this.state.remoteDataType?.description
+ remoteDataType?.description
)
: null}
-
-
- Step 2: Enter the URL of the data file or web
- service
-
-
-
+ {remoteDataType?.customComponent
+ ? this.renderCustomComponent(remoteDataType?.customComponent)
+ : this.renderDefaultForWebDataType(t)}
>
)}
);
- },
+ }
+
+ renderCustomComponent(CustomComponent) {
+ return ;
+ }
+
+ renderDefaultForWebDataType(t) {
+ return (
+ <>
+
+
+ Step 2: Enter the URL of the data file or web
+ service
+
+
+
+ >
+ );
+ }
render() {
return {this.renderPanels()}
;
}
-});
+}
/**
* @param extensions - string[]
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/CesiumIonConnector.tsx b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/CesiumIonConnector.tsx
new file mode 100644
index 00000000000..a19f0539fdf
--- /dev/null
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/CesiumIonConnector.tsx
@@ -0,0 +1,724 @@
+import React from "react";
+import { observer } from "mobx-react";
+import URI from "urijs";
+import { string } from "prop-types";
+import { Trans, useTranslation } from "react-i18next";
+import AddDataStyles from "./add-data.scss";
+import Styles from "./cesium-ion-connector.scss";
+import upsertModelFromJson from "../../../../Models/Definition/upsertModelFromJson";
+import CatalogMemberFactory from "../../../../Models/Catalog/CatalogMemberFactory";
+import CommonStrata from "../../../../Models/Definition/CommonStrata";
+import addUserCatalogMember from "../../../../Models/Catalog/addUserCatalogMember";
+import Dropdown from "../../../Generic/Dropdown";
+import Icon from "../../../../Styled/Icon";
+import classNames from "classnames";
+import { RawButton } from "../../../../Styled/Button";
+import styled from "styled-components";
+import { useViewState } from "../../../Context";
+import TimeVarying from "../../../../ModelMixins/TimeVarying";
+import isDefined from "../../../../Core/isDefined";
+import Terria from "../../../../Models/Terria";
+
+interface CesiumIonToken {
+ id?: string;
+ name?: string;
+ uniqueName?: string; // we populate this one ourselves
+ token?: string;
+ dateAdded?: string;
+ dateModified?: string;
+ dateLastUsed?: string;
+ assetIds?: number[];
+ isDefault?: boolean;
+ allowedUrls?: string[];
+ scopes?: string[];
+}
+
+interface CesiumIonAsset {
+ id?: number;
+ name?: string;
+ uniqueName?: string; // we populate this one ourselves
+ description?: string;
+ type?: string;
+ bytes?: number;
+ dateAdded?: string;
+ status?: string;
+ percentComplete?: number;
+ archivable?: boolean;
+ exportable?: boolean;
+}
+
+const ActionButton = styled(RawButton)`
+ svg {
+ height: 20px;
+ width: 20px;
+ margin: 5px;
+ fill: ${(p) => p.theme.charcoalGrey};
+ }
+
+ &:hover,
+ &:focus {
+ svg {
+ fill: ${(p) => p.theme.modalHighlight};
+ }
+ }
+`;
+
+/**
+ * An interface getting and setting the user's Cesium ion login token obtained via OAuth2.
+ */
+interface LoginTokenPersistence {
+ get(): string | null;
+ set(token: string): void;
+ clear(): void;
+}
+
+class LoginTokenPersistenceInLocalStorage implements LoginTokenPersistence {
+ private storageName = "cesium-ion-login-token";
+
+ public get(): string | null {
+ return localStorage.getItem(this.storageName) ?? "";
+ }
+
+ public set(token: string) {
+ localStorage.setItem(this.storageName, token);
+ }
+
+ public clear() {
+ localStorage.removeItem(this.storageName);
+ }
+}
+
+class LoginTokenPersistenceInSessionStorage implements LoginTokenPersistence {
+ private storageName = "cesium-ion-login-token";
+
+ public get(): string | null {
+ return sessionStorage.getItem(this.storageName) ?? "";
+ }
+
+ public set(token: string) {
+ sessionStorage.setItem(this.storageName, token);
+ }
+
+ public clear() {
+ sessionStorage.removeItem(this.storageName);
+ }
+}
+
+class LoginTokenPersistenceInPage implements LoginTokenPersistence {
+ private loginToken: string | null = null;
+
+ public get(): string | null {
+ return this.loginToken;
+ }
+
+ public set(token: string) {
+ this.loginToken = token;
+ }
+
+ public clear() {
+ this.loginToken = null;
+ }
+}
+
+const loginTokenPersistenceTypes = {
+ page: new LoginTokenPersistenceInPage(),
+ sessionStorage: new LoginTokenPersistenceInSessionStorage(),
+ localStorage: new LoginTokenPersistenceInLocalStorage()
+};
+
+const loginTokenPersistenceLookup: {
+ [key: string]: LoginTokenPersistence | undefined;
+} = loginTokenPersistenceTypes;
+
+const defaultUserProfile = {
+ id: 0,
+ scopes: [],
+ username: "",
+ email: "",
+ emailVerified: false,
+ avatar: string,
+ storage: {}
+};
+
+function CesiumIonConnector() {
+ const viewState = useViewState();
+ const { t } = useTranslation();
+
+ const loginTokenPersistence =
+ loginTokenPersistenceLookup[
+ viewState.terria.configParameters.cesiumIonLoginTokenPersistence ?? ""
+ ] ?? loginTokenPersistenceTypes.page;
+
+ const [codeChallenge, setCodeChallenge] = React.useState({
+ value: "",
+ hash: ""
+ });
+
+ const [tokens, setTokens] = React.useState([]);
+ const [isLoadingTokens, setIsLoadingTokens] = React.useState(false);
+ const [assets, setAssets] = React.useState([]);
+ const [isLoadingAssets, setIsLoadingAssets] = React.useState(false);
+
+ // This is the Cesium ion token representing the currently logged-in user, as obtained via
+ // an OAuth2 Authorization Code Grant flow with Cesium ion.
+ const [loginToken, setLoginToken] = React.useState(
+ loginTokenPersistence.get() ?? ""
+ );
+
+ const [userProfile, setUserProfile] = React.useState(defaultUserProfile);
+ const [isLoadingUserProfile, setIsLoadingUserProfile] =
+ React.useState(false);
+
+ React.useEffect(() => {
+ if (!crypto || !crypto.subtle) return;
+
+ const codeChallenge = [...crypto.getRandomValues(new Uint8Array(32))]
+ .map((x) => x.toString(16).padStart(2, "0"))
+ .join("");
+
+ crypto.subtle
+ .digest("SHA-256", new TextEncoder().encode(codeChallenge))
+ .then((hash) => {
+ setCodeChallenge({
+ value: codeChallenge,
+ hash: btoa(String.fromCharCode(...new Uint8Array(hash)))
+ .replace(/\+/g, "-")
+ .replace(/\//g, "_")
+ .replace(/[=]/g, "")
+ });
+ });
+ }, []);
+
+ React.useEffect(() => {
+ if (loginToken.length === 0) return;
+
+ setIsLoadingUserProfile(true);
+
+ fetch("https://api.cesium.com/v1/me", {
+ headers: {
+ Authorization: `Bearer ${loginToken}`
+ }
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((profile) => {
+ if (profile && profile.username) {
+ setUserProfile(profile);
+ } else {
+ setUserProfile(defaultUserProfile);
+ }
+ setIsLoadingUserProfile(false);
+ });
+ }, [loginToken]);
+
+ React.useEffect(() => {
+ if (loginToken.length === 0) return;
+
+ setIsLoadingAssets(true);
+
+ fetch("https://api.cesium.com/v1/assets", {
+ headers: {
+ Authorization: `Bearer ${loginToken}`
+ }
+ })
+ .then((response) => response.json())
+ .then((assets: { items: CesiumIonAsset[] }) => {
+ if (assets.items) {
+ assets.items.forEach((item) => {
+ item.uniqueName = `${item.name} (${item.id})`;
+ });
+ setAssets(assets.items);
+ }
+
+ setIsLoadingAssets(false);
+ });
+ }, [loginToken]);
+
+ React.useEffect(() => {
+ if (
+ !viewState.terria.configParameters.cesiumIonAllowSharingAddedAssets ||
+ loginToken.length === 0
+ ) {
+ return;
+ }
+
+ setIsLoadingTokens(true);
+
+ fetch("https://api.cesium.com/v2/tokens", {
+ headers: {
+ Authorization: `Bearer ${loginToken}`
+ }
+ })
+ .then((response) => response.json())
+ .then((tokens: { items: CesiumIonToken[] }) => {
+ if (tokens.items) {
+ tokens.items.forEach((item) => {
+ item.uniqueName = `${item.name} (${item.id})`;
+ });
+ setTokens(tokens.items);
+ }
+ setIsLoadingTokens(false);
+ });
+ }, [
+ loginToken,
+ viewState.terria.configParameters.cesiumIonAllowSharingAddedAssets
+ ]);
+
+ let selectedToken = viewState.currentCesiumIonToken
+ ? tokens.find((token) => token.id === viewState.currentCesiumIonToken)
+ : undefined;
+
+ if (selectedToken === undefined && tokens.length > 0) {
+ selectedToken = tokens[0];
+ }
+
+ const setSelectedToken = (token: CesiumIonToken) => {
+ viewState.currentCesiumIonToken = token.id;
+ };
+
+ if (!crypto || !crypto.subtle) {
+ return (
+
+ This service is not currently available. The most likely cause is that
+ this web page is being accessed with `http` instead of `https`.
+
+ );
+ }
+
+ const dropdownTheme = {
+ list: AddDataStyles.dropdownList,
+ icon: ,
+ dropdown: Styles.dropDown,
+ button: Styles.dropDownButton
+ };
+
+ return (
+ <>
+
+
+ Step 2:
+
+
+ {loginToken.length > 0
+ ? renderConnectedOrConnecting()
+ : renderDisconnected()}
+ >
+ );
+
+ function renderConnectedOrConnecting() {
+ return (
+ <>
+ {isLoadingUserProfile ? (
+
+ Loading user profile information...
+
+ ) : (
+
+ Connected to Cesium ion as {userProfile.username}
+
+ )}
+
+ Disconnect
+
+ {userProfile.username.length > 0 && renderConnected()}
+ >
+ );
+ }
+
+ function renderConnected() {
+ const isAssetAccessibleBySelectedToken = (asset: CesiumIonAsset) => {
+ if (!selectedToken) {
+ if (viewState.terria.configParameters.cesiumIonAllowSharingAddedAssets)
+ return false;
+ else return true;
+ }
+
+ if (asset.id === undefined) return true;
+
+ if (selectedToken.assetIds === undefined) {
+ // Token allows access to all assets
+ return true;
+ }
+
+ return selectedToken.assetIds.indexOf(asset.id) >= 0;
+ };
+
+ return (
+ <>
+ {renderTokenSelector()}
+ {isLoadingAssets ? (
+ Loading asset list...
+ ) : (
+
+
+
+
+ Name
+ Type
+
+ {assets
+ .filter(isAssetAccessibleBySelectedToken)
+ .map(renderAssetRow)}
+
+
+ )}
+ >
+ );
+ }
+
+ function renderTokenSelector() {
+ if (!viewState.terria.configParameters.cesiumIonAllowSharingAddedAssets)
+ return undefined;
+
+ return (
+ <>
+
+ Cesium ion Token:
+
+ {isLoadingTokens ? (
+ Loading token list...
+ ) : (
+
+ )}
+
+ {renderTokenWarning()}
+
+ >
+ );
+ }
+
+ function renderDisconnected() {
+ return (
+
+
+ Access globe high-resolution 3D content, including photogrammetry,
+ terrain, imagery and buildings. Bring your own data for tiling,
+ hosting and streaming to {viewState.terria.appName}.
+
+
+
+ Connect to Cesium ion
+
+
+
+ );
+ }
+
+ function renderTokenWarning() {
+ if (!selectedToken) return;
+
+ const dangerousScopes = [];
+ for (const scope of selectedToken.scopes ?? []) {
+ // Only these scopes are "safe".
+ if (scope !== "assets:read" && scope !== "geocode") {
+ dangerousScopes.push(scope);
+ }
+ }
+
+ if (dangerousScopes.length > 0) {
+ return (
+ <>
+ DO NOT USE THIS TOKEN! It allows access to your{" "}
+
+ Cesium ion account
+ {" "}
+ using the following scopes that provide potentially sensitive
+ information or allow changes to be made to your account:{" "}
+ {dangerousScopes.join(", ")}
+ >
+ );
+ }
+
+ if (!siteMatchesAllowedUrls(selectedToken)) {
+ return (
+ <>
+ This token cannot be used with this map because the map is not in the
+ token's list of allowed URLs in your{" "}
+
+ Cesium ion account
+
+ .
+ >
+ );
+ }
+
+ let numberOfAssetsAccessible = -1;
+ if (selectedToken.assetIds) {
+ numberOfAssetsAccessible = selectedToken.assetIds.length;
+ }
+
+ return (
+ <>
+ This token allows access to{" "}
+
+ {numberOfAssetsAccessible < 0 ? "every" : numberOfAssetsAccessible}
+ {" "}
+ {numberOfAssetsAccessible <= 1 ? "asset" : "assets"} in your{" "}
+
+ Cesium ion account
+
+ .
+ >
+ );
+ }
+
+ function renderAssetRow(asset: CesiumIonAsset) {
+ return (
+
+
+
+
+
+
+ {asset.name}
+ {asset.type}
+
+ );
+ }
+
+ function connect() {
+ const clientID =
+ viewState.terria.configParameters.cesiumIonOAuth2ApplicationID;
+ const redirectUri = URI("build/TerriaJS/cesium-ion-oauth2.html")
+ .absoluteTo(window.location.href)
+ .fragment("")
+ .query("")
+ .toString();
+
+ const codeChallengeValue = codeChallenge.value;
+ const codeChallengeHash = codeChallenge.hash;
+
+ const state = [...crypto.getRandomValues(new Uint8Array(16))]
+ .map((x) => x.toString(16).padStart(2, "0"))
+ .join("");
+
+ const uri = new URI("https://ion.cesium.com/oauth").addQuery({
+ response_type: "code",
+ client_id: clientID,
+ scope: "assets:read assets:list tokens:read profile:read",
+ redirect_uri: redirectUri,
+ state: state,
+ code_challenge: codeChallengeHash,
+ code_challenge_method: "S256"
+ });
+
+ (window as any)["cesiumIonOAuth2_" + state] = function (code: string) {
+ fetch("https://api.cesium.com/oauth/token", {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({
+ grant_type: "authorization_code",
+ client_id: clientID,
+ code: code,
+ redirect_uri: redirectUri,
+ code_verifier: codeChallengeValue
+ })
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((response) => {
+ loginTokenPersistence.set(response.access_token);
+ setLoginToken(response.access_token ?? "");
+ });
+ };
+
+ window.open(uri.toString(), "_blank", "popup=yes,width=600,height=600");
+ }
+
+ function disconnect() {
+ loginTokenPersistence.clear();
+ setLoginToken("");
+ setUserProfile(defaultUserProfile);
+ }
+
+ function addToMap(
+ terria: Terria,
+ asset: CesiumIonAsset,
+ event: React.MouseEvent
+ ) {
+ // If the asset may be shared, the user must choose a suitable token.
+ // If not, we can access the asset using the login token.
+ const allowSharing =
+ viewState.terria.configParameters.cesiumIonAllowSharingAddedAssets;
+ const assetToken = allowSharing
+ ? selectedToken
+ : { token: loginToken, name: `${userProfile.username}'s login token` };
+ if (!assetToken) return;
+
+ const definition = createCatalogItemDefinitionFromAsset(
+ terria,
+ asset,
+ assetToken
+ );
+ if (!definition) return;
+
+ const newItem = upsertModelFromJson(
+ CatalogMemberFactory,
+ viewState.terria,
+ "",
+ terria.configParameters.cesiumIonAllowSharingAddedAssets
+ ? CommonStrata.user
+ : CommonStrata.definition,
+ definition,
+ {}
+ ).throwIfUndefined({
+ message: `An error occurred trying to add asset: ${asset.name}`
+ });
+
+ const keepCatalogOpen = event.shiftKey || event.ctrlKey;
+
+ addUserCatalogMember(viewState.terria, Promise.resolve(newItem)).then(
+ (addedItem) => {
+ if (addedItem) {
+ if (TimeVarying.is(addedItem)) {
+ viewState.terria.timelineStack.addToTop(addedItem);
+ }
+ }
+
+ if (!keepCatalogOpen) {
+ viewState.closeCatalog();
+ }
+ }
+ );
+ }
+
+ function createCatalogItemDefinitionFromAsset(
+ terria: Terria,
+ asset: CesiumIonAsset,
+ token: CesiumIonToken
+ ) {
+ let type = "";
+ const extras: any = {};
+ switch (asset.type) {
+ case "3DTILES":
+ type = "3d-tiles";
+ break;
+ case "GLTF":
+ type = "gltf";
+ // TODO
+ extras.origin = {
+ longitude: 0.0,
+ latitude: 0.0,
+ height: 0.0
+ };
+ break;
+ case "IMAGERY":
+ type = "ion-imagery";
+ break;
+ case "TERRAIN":
+ type = "cesium-terrain";
+ break;
+ case "CZML":
+ type = "czml";
+ break;
+ case "KML":
+ type = "kml";
+ break;
+ case "GEOJSON":
+ type = "geojson";
+ break;
+ }
+
+ if (type === "") return undefined;
+
+ return {
+ name: asset.name ?? "Unnamed",
+ type: type,
+ shareable:
+ terria.configParameters.cesiumIonAllowSharingAddedAssets ?? false,
+ description: asset.description ?? "",
+ ionAssetId: asset.id ?? 0,
+ ionAccessToken: token.token,
+ info: [
+ {
+ name: "Cesium ion Account",
+ content: userProfile.username
+ },
+ {
+ name: "Cesium ion Token",
+ content: token.name ?? token.id
+ }
+ ],
+ ...extras
+ };
+ }
+}
+
+function siteMatchesAllowedUrls(token: CesiumIonToken) {
+ if (!isDefined(token.allowedUrls)) {
+ return true;
+ }
+
+ const current = new URI(window.location.href);
+
+ for (const allowedUrl of token.allowedUrls) {
+ let allowed;
+
+ try {
+ allowed = new URI(allowedUrl);
+ } catch (e) {
+ continue;
+ }
+
+ const currentHostname = current.hostname();
+ const allowedHostname = allowed.hostname();
+
+ // Current hostname must either match the allowed one exactly, or be a subdomain of the allowed one.
+ const hostnameValid =
+ currentHostname === allowedHostname ||
+ (currentHostname.endsWith(allowedHostname) &&
+ currentHostname[currentHostname.length - allowedHostname.length - 1] ===
+ ".");
+ if (!hostnameValid) continue;
+
+ // If the current has a port, the allowed must match.
+ if (current.port().length > 0 && current.port() !== allowed.port())
+ continue;
+
+ // The current path must start with the allowed path.
+ if (!current.path().startsWith(allowed.path())) continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+const CesiumIonConnectorObserver = observer(CesiumIonConnector);
+export default CesiumIonConnectorObserver;
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/add-data.scss b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/add-data.scss
index 10ac31ca230..7a572699645 100644
--- a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/add-data.scss
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/add-data.scss
@@ -4,11 +4,12 @@
@include empty-module("inner");
.tab-panels {
- width: 50%;
+ width: fit-content;
+ min-width: 50%;
max-width: 600px;
margin: 3vh auto;
text-align: left;
- padding-top: 10vh;
+ //padding-top: 10vh;
}
.tab-panel {
text-align: left;
@@ -59,6 +60,7 @@
.dropdown {
&__list {
height: 250px;
+ overflow-y: visible;
}
@media (max-height: 800px) {
&__list {
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss
new file mode 100644
index 00000000000..972d3134962
--- /dev/null
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss
@@ -0,0 +1,35 @@
+@import "~terriajs-variables";
+@import "../../../../Sass/common/mixins";
+
+.connect-button {
+ composes: btn from "../../../../Sass/common/_buttons.scss";
+ composes: btn-transparent from "../../../../Sass/common/_buttons.scss";
+ composes: btn-primary from "../../../../Sass/common/_buttons.scss";
+ width: 200px;
+}
+
+.token-warning {
+ color: $warning;
+ font-family: $font-base;
+ font-size: 0.9em;
+}
+
+.token-warning-hidden {
+ visibility: hidden;
+}
+
+.drop-down {
+ height: 40px;
+}
+
+.drop-down-button {
+ height: 100%;
+}
+
+.assets-list {
+ overflow-y: auto;
+}
+
+.add-asset-button {
+ vertical-align: middle;
+}
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss.d.ts b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss.d.ts
new file mode 100644
index 00000000000..ddc99df9ca5
--- /dev/null
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/cesium-ion-connector.scss.d.ts
@@ -0,0 +1,20 @@
+// This file is automatically generated.
+// Please do not change this file!
+interface CssExports {
+ 'add-asset-button': string;
+ 'addAssetButton': string;
+ 'assets-list': string;
+ 'assetsList': string;
+ 'connect-button': string;
+ 'connectButton': string;
+ 'drop-down': string;
+ 'drop-down-button': string;
+ 'dropDown': string;
+ 'dropDownButton': string;
+ 'token-warning': string;
+ 'token-warning-hidden': string;
+ 'tokenWarning': string;
+ 'tokenWarningHidden': string;
+}
+declare var cssExports: CssExports;
+export = cssExports;
diff --git a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/my-data-tab.scss b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/my-data-tab.scss
index a91d093dfec..f61a3073fcb 100644
--- a/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/my-data-tab.scss
+++ b/lib/ReactViews/ExplorerWindow/Tabs/MyDataTab/my-data-tab.scss
@@ -29,7 +29,7 @@
margin: 15px;
height: calc(100% - 30px);
width: calc(100% - 30px);
- overflow: hidden;
+ overflow: auto;
background: $modal-secondary-bg;
text-align: center;
color: $dark-lighter;
diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx
index 437ed11cab6..6cc12daafbe 100644
--- a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx
+++ b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx
@@ -8,8 +8,7 @@ import ViewState from "../../ReactViewModels/ViewState";
import Icon from "../../Styled/Icon";
import { withViewState } from "../Context";
import Styles from "./feature-info-download.scss";
-
-const Dropdown = require("../Generic/Dropdown");
+import Dropdown from "../Generic/Dropdown";
class FeatureInfoDownload extends React.Component<{
data: JsonObject;
@@ -55,7 +54,6 @@ class FeatureInfoDownload extends React.Component<{
button: Styles.dropdownButton,
icon: icon
}}
- buttonClassName={Styles.btn}
>
{t("featureInfo.download")}
diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx
index 2b1a2bcf3ec..da5e71a2d5c 100644
--- a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx
+++ b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx
@@ -144,7 +144,7 @@ export class FeatureInfoSection extends React.Component {
this.removeFeatureChangedSubscription?.();
this.removeFeatureChangedSubscription =
feature.definitionChanged.addEventListener(
- ((changedFeature: TerriaFeature) => {
+ ((_changedFeature: TerriaFeature) => {
runInAction(() => {
this.featureChangedCounter++;
});
diff --git a/lib/ReactViews/FeatureInfo/getFeatureProperties.ts b/lib/ReactViews/FeatureInfo/getFeatureProperties.ts
index 7a2e6b7a318..a2e60d1300a 100644
--- a/lib/ReactViews/FeatureInfo/getFeatureProperties.ts
+++ b/lib/ReactViews/FeatureInfo/getFeatureProperties.ts
@@ -84,7 +84,9 @@ function parseValues(properties: JsonObject) {
try {
val = JSON.parse(val as string);
} catch (e) {
- return;
+ console.warn(
+ `Error parsing JSON in feature properties "${key}": ${e}\nWill use string value instead: "${val}"`
+ );
}
}
result[key] = val;
diff --git a/lib/ReactViews/FeatureInfo/mustacheExpressions.ts b/lib/ReactViews/FeatureInfo/mustacheExpressions.ts
index cd48fb66418..43613ad0b88 100644
--- a/lib/ReactViews/FeatureInfo/mustacheExpressions.ts
+++ b/lib/ReactViews/FeatureInfo/mustacheExpressions.ts
@@ -87,7 +87,7 @@ export function mustacheRenderPartialByName(
templateData: object
): MustacheFunction {
return () => {
- return mustacheJsonSubOptions((value, options) => {
+ return mustacheJsonSubOptions((value, _options) => {
if (!isJsonString(value)) return `${value}`;
if (partials && typeof partials[value] === "string") {
return Mustache.render(partials[value], templateData);
diff --git a/lib/ReactViews/Generic/CloseButton.tsx b/lib/ReactViews/Generic/CloseButton.tsx
new file mode 100644
index 00000000000..f38f209e7bf
--- /dev/null
+++ b/lib/ReactViews/Generic/CloseButton.tsx
@@ -0,0 +1,34 @@
+// for all the panels and modals we will eventually normalise
+import React from "react";
+import styled from "styled-components";
+// import Box from "../../Styled/Box";
+import Icon from "../../Styled/Icon";
+import { ButtonProps, RawButton } from "../../Styled/Button";
+
+const StyledCloseButton = styled(RawButton)`
+ ${(p: any) => !p.noAbsolute && `position: absolute;`}
+ // width: 20px;
+ // height: 20px;
+ width: 14px;
+ height: 14px;
+ ${(p: any) =>
+ p.topRight &&
+ `
+ top: 15px;
+ right:15px;
+ `}
+ svg {
+ // fill: ${(p) => p.color || p.theme.darkWithOverlay};
+ fill: ${(p) => p.color};
+ }
+`;
+
+const CloseButton = (props: ButtonProps) => {
+ return (
+
+
+
+ );
+};
+
+export default CloseButton;
diff --git a/lib/ReactViews/Generic/Dropdown.d.ts b/lib/ReactViews/Generic/Dropdown.d.ts
new file mode 100644
index 00000000000..a1ea178b042
--- /dev/null
+++ b/lib/ReactViews/Generic/Dropdown.d.ts
@@ -0,0 +1,16 @@
+import React from "react";
+
+interface DropdownProps {
+ theme?: any;
+ options?: any[];
+ selected?: any;
+ selectOption?: (o: any, i: number) => void;
+ textProperty?: string;
+ matchWidth?: boolean;
+ children?: any;
+ disabled?: boolean;
+}
+
+declare class Dropdown extends React.Component {}
+
+export default Dropdown;
diff --git a/lib/ReactViews/Generic/Dropdown.jsx b/lib/ReactViews/Generic/Dropdown.jsx
index 8fa71647881..427107c16ad 100644
--- a/lib/ReactViews/Generic/Dropdown.jsx
+++ b/lib/ReactViews/Generic/Dropdown.jsx
@@ -175,4 +175,4 @@ const Dropdown = createReactClass({
}
});
-module.exports = Dropdown;
+export default Dropdown;
diff --git a/lib/ReactViews/Generic/Prompt.d.ts b/lib/ReactViews/Generic/Prompt.d.ts
new file mode 100644
index 00000000000..29a61a8cca6
--- /dev/null
+++ b/lib/ReactViews/Generic/Prompt.d.ts
@@ -0,0 +1,20 @@
+import React from "react";
+
+interface PropsType {
+ content: React.ReactNode;
+ isVisible: boolean;
+ displayDelay: number;
+ dismissText: string;
+ dismissAction: () => void;
+ centered?: boolean;
+ caretTopOffset?: number;
+ caretLeftOffset?: number;
+ caretSize?: number;
+ promptWidth?: number;
+ promptTopOffset?: number;
+ promptLeftOffset?: number;
+}
+
+declare class Prompt extends React.PureComponent {}
+
+export default Prompt;
diff --git a/lib/ReactViews/Generic/Timer/drawTimer.js b/lib/ReactViews/Generic/Timer/drawTimer.js
index c1f89ebdf76..0d8fef7a8f3 100644
--- a/lib/ReactViews/Generic/Timer/drawTimer.js
+++ b/lib/ReactViews/Generic/Timer/drawTimer.js
@@ -155,7 +155,7 @@ export function createTimer(
* @param {string} containerId The id of the element to insert the timer into.
* @param {string} elapsedTimeClass A class for styling the animation that fills the timer as it runs.
* @param {string} backgroundClass A class for styling the timer's background circle.
- * @param {string} [elapsed=0] How much time (in seconds) has already passed.
+ * @param {number} [elapsed=0] How much time (in seconds) has already passed.
*/
export function startTimer(
radius,
diff --git a/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx b/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.tsx
similarity index 100%
rename from lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx
rename to lib/ReactViews/HelpScreens/SatelliteHelpPrompt.tsx
diff --git a/lib/ReactViews/Hooks/useRefForTerria.ts b/lib/ReactViews/Hooks/useRefForTerria.ts
index 6045bf11063..3a0a2213842 100644
--- a/lib/ReactViews/Hooks/useRefForTerria.ts
+++ b/lib/ReactViews/Hooks/useRefForTerria.ts
@@ -17,6 +17,7 @@ export function useRefForTerria(
return function removeRefFromTerria() {
viewState.deleteAppRef(refName);
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [ref]);
return ref;
}
diff --git a/lib/ReactViews/Hooks/useWindowSize.ts b/lib/ReactViews/Hooks/useWindowSize.ts
index 35a005de815..34dc84c8ddc 100644
--- a/lib/ReactViews/Hooks/useWindowSize.ts
+++ b/lib/ReactViews/Hooks/useWindowSize.ts
@@ -31,6 +31,7 @@ export function useWindowSize({ debounceOverride }: UseWindowSizeOptions) {
return () => {
window.removeEventListener("resize", resizeListener);
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
return width;
diff --git a/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx
index 5800d416b4b..fa4637a80d4 100644
--- a/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx
+++ b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx
@@ -42,6 +42,7 @@ export const MapCredits: FC = observer(
}
}
);
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [currentViewer]);
if (currentViewer.type === "none") {
diff --git a/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx
index e59651efb26..4b5f4dd7456 100644
--- a/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx
+++ b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx
@@ -7,7 +7,6 @@ import { useTheme } from "styled-components";
import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2";
import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic";
import CesiumEvent from "terriajs-cesium/Source/Core/Event";
-import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp";
import Scene from "terriajs-cesium/Source/Scene/Scene";
import isDefined from "../../../Core/isDefined";
import Box from "../../../Styled/Box";
@@ -42,7 +41,7 @@ export const DistanceLegend: FC = observer(
useEffect(() => {
const viewerSubscriptions: CesiumEvent.RemoveCallback[] = [];
-
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
removeUpdateSubscription = addUpdateSubscription();
return () => {
@@ -91,8 +90,6 @@ export const DistanceLegend: FC = observer(
};
const updateDistanceLegendCesium = (scene: Scene) => {
- const now = getTimestamp();
-
// Find the distance between two pixels at the bottom center of the screen.
const width = scene.canvas.clientWidth;
const height = scene.canvas.clientHeight;
@@ -160,7 +157,7 @@ export const DistanceLegend: FC = observer(
.distanceTo(map.containerPointToLatLng([maxPixelWidth, halfHeight]));
runInAction(() => (terria.mainViewer.scale = maxMeters / 100));
- // @ts-expect-error
+ // @ts-expect-error Accessing private method
const meters = L.control.scale()._getRoundNum(maxMeters);
const label = meters < 1000 ? meters + " m" : meters / 1000 + " km";
diff --git a/lib/ReactViews/Map/MapColumn.tsx b/lib/ReactViews/Map/MapColumn.tsx
index 0135fb2a5da..1d0f0f12fc1 100644
--- a/lib/ReactViews/Map/MapColumn.tsx
+++ b/lib/ReactViews/Map/MapColumn.tsx
@@ -16,7 +16,6 @@ import { TerriaViewerWrapper } from "./TerriaViewerWrapper";
import Toast from "./Toast";
interface IMapColumnProps {
- customFeedbacks: any;
animationDuration: number;
customElements: any;
}
@@ -26,7 +25,7 @@ interface IMapColumnProps {
* the timeline and charts.
*/
export const MapColumn: FC = observer(
- ({ customFeedbacks, customElements, animationDuration }) => {
+ ({ customElements, animationDuration }) => {
const viewState = useViewState();
const { t } = useTranslation();
@@ -60,7 +59,6 @@ export const MapColumn: FC = observer(
`}
>
{
`}
>
{
// this.props.viewState.showHelpPanel();
diff --git a/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.d.ts b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.d.ts
new file mode 100644
index 00000000000..3ff142f46bc
--- /dev/null
+++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.d.ts
@@ -0,0 +1,10 @@
+import ViewState from "../../../../../ReactViewModels/ViewState";
+import React from "react";
+
+interface PropsType {
+ viewState: ViewState;
+ handleHelp?: () => void;
+ onClose: () => void;
+}
+
+export declare const GyroscopeGuidance: React.FC;
diff --git a/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx
index fa8e9386e74..4697d8c1736 100644
--- a/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx
+++ b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx
@@ -180,7 +180,7 @@ class ZoomControlBase extends React.Component {
}
render() {
- const { t, theme } = this.props;
+ const { t } = this.props;
return (
;
+export default MenuBar;
diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.d.ts b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.d.ts
new file mode 100644
index 00000000000..807fe6c1d6c
--- /dev/null
+++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.d.ts
@@ -0,0 +1,4 @@
+import React from "react";
+
+declare class HelpPanel extends React.Component<{}> {}
+export default HelpPanel;
diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx
index 6d31dba92ab..3d984b6f92a 100644
--- a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx
+++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx
@@ -76,7 +76,7 @@ class HelpPanel extends React.Component {
diff --git a/lib/ReactViews/Map/Panels/HelpPanel/VideoGuide.d.ts b/lib/ReactViews/Map/Panels/HelpPanel/VideoGuide.d.ts
new file mode 100644
index 00000000000..de29f4976d5
--- /dev/null
+++ b/lib/ReactViews/Map/Panels/HelpPanel/VideoGuide.d.ts
@@ -0,0 +1,14 @@
+import React from "react";
+import ViewState from "../../../../ReactViewModels/ViewState";
+
+interface PropsType {
+ viewState: ViewState;
+ videoName: string;
+ videoLink: string;
+ background: string;
+ // A number between 0 and 1.0
+ backgroundOpacity?: number;
+}
+
+declare class VideoGuide extends React.Component {}
+export default VideoGuide;
diff --git a/lib/ReactViews/Map/Panels/SharePanel/BuildShareLink.ts b/lib/ReactViews/Map/Panels/SharePanel/BuildShareLink.ts
index 308bafc2c89..9c4adee89dd 100644
--- a/lib/ReactViews/Map/Panels/SharePanel/BuildShareLink.ts
+++ b/lib/ReactViews/Map/Panels/SharePanel/BuildShareLink.ts
@@ -23,6 +23,7 @@ import {
import Terria from "../../../../Models/Terria";
import ViewState from "../../../../ReactViewModels/ViewState";
import getDereferencedIfExists from "../../../../Core/getDereferencedIfExists";
+import CatalogMemberMixin from "../../../../ModelMixins/CatalogMemberMixin";
/** User properties (generated from URL hash parameters) to add to share link URL in PRODUCTION environment.
* If in Dev, we add all user properties.
@@ -253,12 +254,23 @@ export function isShareable(terria: Terria) {
return function (modelId: string) {
const model = terria.getModelById(BaseModel, modelId);
+ if (CatalogMemberMixin.isMixedInto(model) && !model.shareable) {
+ return false;
+ }
+
// If this is a Reference, then use the model.target, otherwise use the model
const dereferenced =
- typeof model === undefined
+ typeof model === "undefined"
? model
: getDereferencedIfExists(terria.getModelById(BaseModel, modelId)!);
+ if (
+ CatalogMemberMixin.isMixedInto(dereferenced) &&
+ !dereferenced.shareable
+ ) {
+ return false;
+ }
+
return (
model &&
((HasLocalData.is(dereferenced) && !dereferenced.hasLocalData) ||
diff --git a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx
index 03323501baf..b871d767610 100644
--- a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx
+++ b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx
@@ -145,10 +145,12 @@ const PrintView = (props: Props) => {
props.window.document.head.appendChild(mkStyle(styles));
props.window.document.body.appendChild(rootNode.current);
props.window.addEventListener("beforeunload", props.closeCallback);
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.window]);
useEffect(() => {
setScreenshot(viewState.terria.currentViewer.captureScreenshot());
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.window]);
useEffect(() => {
diff --git a/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrl.tsx b/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrl.tsx
index 3979f1cdb65..23b92372d74 100644
--- a/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrl.tsx
+++ b/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrl.tsx
@@ -1,5 +1,4 @@
import React, {
- forwardRef,
useEffect,
useImperativeHandle,
useState,
@@ -39,7 +38,7 @@ export interface IShareUrlRef {
shorteningInProgress: boolean;
}
-export const ShareUrl = forwardRef<
+export const ShareUrl = React.forwardRef<
IShareUrlRef,
PropsWithChildren
>(function ShareUrl(
@@ -68,6 +67,7 @@ export const ShareUrl = forwardRef<
url: shareUrl,
shorteningInProgress: shorteningInProgress
}),
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[forwardRef, shareUrl, shorteningInProgress]
);
@@ -94,6 +94,7 @@ export const ShareUrl = forwardRef<
})
);
}
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [terria, viewState, shouldShorten, includeStories]);
return (
diff --git a/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrlWarning.tsx b/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrlWarning.tsx
index 4cc0199d510..34eb9301a57 100644
--- a/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrlWarning.tsx
+++ b/lib/ReactViews/Map/Panels/SharePanel/ShareUrl/ShareUrlWarning.tsx
@@ -60,8 +60,8 @@ export const ShareUrlWarning: FC = observer(
The following data sources will NOT be shared because they include
- data from this local system. To share these data sources, publish
- their data on a web server and{" "}
+ data from this local system or from an authenticated online service.
+ To share these data sources, publish their data on a web server and{" "}
add them using a url
.
diff --git a/lib/ReactViews/Map/ProgressBar.tsx b/lib/ReactViews/Map/ProgressBar.tsx
index eedfef26599..82e0cae793d 100644
--- a/lib/ReactViews/Map/ProgressBar.tsx
+++ b/lib/ReactViews/Map/ProgressBar.tsx
@@ -31,6 +31,7 @@ export const ProgressBar: VFC = observer(() => {
return () => {
eventHelper.removeAll();
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
const backgroundColor =
diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts
index 06bd9530428..c8f56bd8ed1 100644
--- a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts
+++ b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts
@@ -103,6 +103,7 @@ export const useDragHook = (
e.preventDefault();
e.stopPropagation();
},
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[viewState]
);
@@ -119,6 +120,7 @@ export const useDragHook = (
e.preventDefault();
e.stopPropagation();
},
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[viewState]
);
diff --git a/lib/ReactViews/Mobile/MobileHeader.d.ts b/lib/ReactViews/Mobile/MobileHeader.d.ts
new file mode 100644
index 00000000000..68eb64b1f86
--- /dev/null
+++ b/lib/ReactViews/Mobile/MobileHeader.d.ts
@@ -0,0 +1,12 @@
+import { i18n } from "i18next";
+import React from "react";
+
+interface PropsType {
+ version?: string;
+ menuLeftItems: React.ReactNode[];
+ menuItems: React.ReactNode[];
+ i18n?: i18n;
+}
+
+declare class MobileHeader extends React.Component {}
+export default MobileHeader;
diff --git a/lib/ReactViews/Notification/notification-window.scss b/lib/ReactViews/Notification/notification-window.scss
index f40c172ddaf..631bfbe316a 100644
--- a/lib/ReactViews/Notification/notification-window.scss
+++ b/lib/ReactViews/Notification/notification-window.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
@import "~terriajs-variables";
@import "../../Sass/common/mixins";
@@ -26,7 +28,7 @@
.notification {
border-radius: $radius-small;
- border: 1px solid darken($dark, 3%);
+ border: 1px solid color.adjust($dark, $lightness: -3%);
// background: $dark;
z-index: 300;
pre {
diff --git a/lib/ReactViews/Preview/Description.d.ts b/lib/ReactViews/Preview/Description.d.ts
new file mode 100644
index 00000000000..0ada6130fcb
--- /dev/null
+++ b/lib/ReactViews/Preview/Description.d.ts
@@ -0,0 +1,11 @@
+import React from "react";
+import { BaseModel } from "../../Models/Definition/Model";
+
+interface PropsType {
+ item: BaseModel;
+ printView?: boolean;
+}
+
+declare class Description extends React.Component {}
+
+export default Description;
diff --git a/lib/ReactViews/Preview/metadata-table.scss b/lib/ReactViews/Preview/metadata-table.scss
index ec2a0eb7126..d70de7c0031 100644
--- a/lib/ReactViews/Preview/metadata-table.scss
+++ b/lib/ReactViews/Preview/metadata-table.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
@import "~terriajs-variables";
@import "../../Sass/common/mixins";
@@ -6,7 +8,7 @@
}
.root table tr:nth-child(odd) {
- background-color: darken($faint-bg, 8%);
+ background-color: color.adjust($faint-bg, $lightness: -8%);
}
.root table tr:nth-child(even) {
background-color: $faint-bg;
diff --git a/lib/ReactViews/PrivateIndicator/PrivateIndicator.jsx b/lib/ReactViews/PrivateIndicator/PrivateIndicator.tsx
similarity index 73%
rename from lib/ReactViews/PrivateIndicator/PrivateIndicator.jsx
rename to lib/ReactViews/PrivateIndicator/PrivateIndicator.tsx
index 06c2cce9781..bb5295f34b2 100644
--- a/lib/ReactViews/PrivateIndicator/PrivateIndicator.jsx
+++ b/lib/ReactViews/PrivateIndicator/PrivateIndicator.tsx
@@ -1,28 +1,24 @@
import React from "react";
-import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
-
import Icon from "../../Styled/Icon";
import IconWrapper from "../../Styled/IconWrapper";
-PrivateIndicator.propTypes = {
- inWorkbench: PropTypes.bool
-};
+interface PropsType {
+ inWorkbench?: boolean;
+}
-export default function PrivateIndicator(props) {
+export default function PrivateIndicator(props: PropsType) {
const { t } = useTranslation();
-
return (
+ fill: ${(p: any) =>
p.inWorkbench ? p.theme.textLight : p.theme.charcoalGrey};
}
`}
diff --git a/lib/ReactViews/Search/SearchBox.jsx b/lib/ReactViews/Search/SearchBox.jsx
index df6b103daff..b27bb8ecb31 100644
--- a/lib/ReactViews/Search/SearchBox.jsx
+++ b/lib/ReactViews/Search/SearchBox.jsx
@@ -135,7 +135,7 @@ export const SearchBox = createReactClass({
glyph={Icon.GLYPHS.close}
styledWidth={"15px"}
fillColor={this.props.theme.charcoalGrey}
- opacity={"0.5"}
+ opacity={0.5}
/>
@@ -167,7 +167,7 @@ export const SearchBox = createReactClass({
glyph={Icon.GLYPHS.search}
styledWidth={"20px"}
fillColor={this.props.theme.charcoalGrey}
- opacity={"0.5"}
+ opacity={0.5}
css={`
position: absolute;
`}
diff --git a/lib/ReactViews/Search/SearchBoxAndResults.d.ts b/lib/ReactViews/Search/SearchBoxAndResults.d.ts
new file mode 100644
index 00000000000..361eb03867c
--- /dev/null
+++ b/lib/ReactViews/Search/SearchBoxAndResults.d.ts
@@ -0,0 +1,22 @@
+import { TFunction } from "i18next";
+import React from "react";
+import Terria from "../../Models/Terria";
+import ViewState from "../../ReactViewModels/ViewState";
+
+interface SearchInDataCatalogPropsType {
+ viewState: ViewState;
+ handleClick: () => void;
+}
+
+export declare const SearchInDataCatalog: React.FC;
+
+interface PropsType {
+ viewState: ViewState;
+ terria: Terria;
+ t?: TFunction;
+ placeholder?: string;
+}
+
+declare class SearchBoxAndResults extends React.Component {}
+
+export default SearchBoxAndResults;
diff --git a/lib/ReactViews/Search/SearchResult.tsx b/lib/ReactViews/Search/SearchResult.tsx
index fb2a6c3465d..17a35e4012c 100644
--- a/lib/ReactViews/Search/SearchResult.tsx
+++ b/lib/ReactViews/Search/SearchResult.tsx
@@ -28,7 +28,7 @@ interface SearchResultProps {
clickAction(): void;
isLastResult: boolean;
locationSearchText: string;
- icon: string;
+ icon: keyof typeof Icon.GLYPHS;
}
const SearchResult: React.FC = (
@@ -69,7 +69,6 @@ const SearchResult: React.FC = (
fillColor={isLightTheme && theme.textDarker}
light={isDarkTheme}
styledWidth={"16px"}
- // @ts-expect-error
glyph={Icon.GLYPHS[props.icon]}
/>
)}
diff --git a/lib/ReactViews/SelectableDimensions/Button.tsx b/lib/ReactViews/SelectableDimensions/Button.tsx
index 5657be1280a..e276c5eb8fb 100644
--- a/lib/ReactViews/SelectableDimensions/Button.tsx
+++ b/lib/ReactViews/SelectableDimensions/Button.tsx
@@ -11,7 +11,7 @@ import AnimatedSpinnerIcon from "../../Styled/AnimatedSpinnerIcon";
export const SelectableDimensionButton: React.FC<{
id: string;
dim: SelectableDimensionButtonModel;
-}> = ({ id, dim }) => {
+}> = ({ dim }) => {
const iconGlyph = dim.icon;
const iconProps = { light: true, styledWidth: "16px", styledHeight: "16px" };
return (
diff --git a/lib/ReactViews/SelectableDimensions/Color.tsx b/lib/ReactViews/SelectableDimensions/Color.tsx
index 9330d6d237b..5881305a380 100644
--- a/lib/ReactViews/SelectableDimensions/Color.tsx
+++ b/lib/ReactViews/SelectableDimensions/Color.tsx
@@ -23,7 +23,7 @@ const debounceSetColorDimensionValue = debounce(
export const SelectableDimensionColor: React.FC<{
id: string;
dim: SelectableDimensionColorModel;
-}> = observer(({ id, dim }) => {
+}> = observer(({ dim }) => {
const [open, setIsOpen] = useState(false);
const { t } = useTranslation();
return (
diff --git a/lib/ReactViews/SelectableDimensions/ColorSchemeOptionRenderer.tsx b/lib/ReactViews/SelectableDimensions/ColorSchemeOptionRenderer.tsx
index f07d1b14688..a5929b48bc3 100644
--- a/lib/ReactViews/SelectableDimensions/ColorSchemeOptionRenderer.tsx
+++ b/lib/ReactViews/SelectableDimensions/ColorSchemeOptionRenderer.tsx
@@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
-import { lab, rgb } from "d3-color";
+import { rgb } from "d3-color";
import * as d3Scale from "d3-scale-chromatic";
import React from "react";
import StandardCssColors from "../../Core/StandardCssColors";
@@ -38,21 +38,18 @@ function ramp(
let colors: string[];
/** This could be used to draw text on top of swatches/ramps */
- let dark;
if (
n &&
(d3Scale as any)[`scheme${name}`] &&
(d3Scale as any)[`scheme${name}`][n]
) {
colors = (d3Scale as any)[`scheme${name}`][n];
- dark = lab(colors[0]).l < 50;
} else {
const interpolate = (d3Scale as any)[`interpolate${name}`];
if (!interpolate) {
return ;
}
colors = [];
- dark = lab(interpolate(0)).l < 50;
for (let i = 0; i < interpolateWidth; ++i) {
colors.push(rgb(interpolate(i / (interpolateWidth - 1))).hex());
}
@@ -111,7 +108,6 @@ function swatches(name: string | undefined) {
}
if (!colors) return ;
const n = colors.length;
- const dark = lab(colors[0]).l < 50;
return (
= observer(({ id, dim }) => {
+}> = observer(({ dim }) => {
const theme = useTheme();
const undefinedOption = {
@@ -96,7 +96,7 @@ export const SelectableDimensionEnum: React.FC<{
export const SelectableDimensionEnumMulti: React.FC<{
id: string;
dim: SelectableDimensionEnumMultiModel;
-}> = observer(({ id, dim }) => {
+}> = observer(({ dim }) => {
const theme = useTheme();
const options = dim.options?.map((option) => ({
diff --git a/lib/ReactViews/SidePanel/FullScreenButton.d.ts b/lib/ReactViews/SidePanel/FullScreenButton.d.ts
new file mode 100644
index 00000000000..0498ca74692
--- /dev/null
+++ b/lib/ReactViews/SidePanel/FullScreenButton.d.ts
@@ -0,0 +1,13 @@
+import React from "react";
+import IElementConfig from "../../Models/IElementConfig";
+
+interface PropsType {
+ btnText: string;
+ minified: boolean;
+ animationDuration?: number;
+ elementConfig?: IElementConfig;
+}
+
+declare class FullScreenButton extends React.Component {}
+
+export default FullScreenButton;
diff --git a/lib/ReactViews/StandardUserInterface/Portal.tsx b/lib/ReactViews/StandardUserInterface/Portal.tsx
index 2a857553d5e..157d6b6f86c 100644
--- a/lib/ReactViews/StandardUserInterface/Portal.tsx
+++ b/lib/ReactViews/StandardUserInterface/Portal.tsx
@@ -22,6 +22,7 @@ type PortalProps = {
*/
export const Portal: React.FC = ({ id, className }) => {
const viewState = useViewState();
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
useEffect(
action(() => {
viewState.portals.set(id, document.getElementById(id));
diff --git a/lib/ReactViews/StandardUserInterface/StandardTheme.jsx b/lib/ReactViews/StandardUserInterface/StandardTheme.tsx
similarity index 78%
rename from lib/ReactViews/StandardUserInterface/StandardTheme.jsx
rename to lib/ReactViews/StandardUserInterface/StandardTheme.tsx
index dca182dfab1..a065688d20e 100644
--- a/lib/ReactViews/StandardUserInterface/StandardTheme.jsx
+++ b/lib/ReactViews/StandardUserInterface/StandardTheme.tsx
@@ -1,8 +1,9 @@
import Variables from "../../Sass/exports/_variables-export.scss";
-
import Mixins from "../../Styled/mixins";
export const terriaTheme = {
...Variables,
...Mixins
};
+
+export type TerriaTheme = typeof terriaTheme;
diff --git a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx
index 495587487f5..727b9de2c43 100644
--- a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx
+++ b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx
@@ -6,7 +6,6 @@ import React, { ReactNode, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { DefaultTheme } from "styled-components";
import combine from "terriajs-cesium/Source/Core/combine";
-import arrayContains from "../../Core/arrayContains";
import ViewState from "../../ReactViewModels/ViewState";
import Disclaimer from "../Disclaimer";
import DragDropFile from "../DragDropFile";
@@ -68,10 +67,7 @@ const StandardUserInterfaceBase: React.FC =
});
const handleDragOver = (e: React.DragEvent) => {
- if (
- !e.dataTransfer.types ||
- !arrayContains(e.dataTransfer.types, "Files")
- ) {
+ if (!e.dataTransfer.types || !e.dataTransfer.types.includes("Files")) {
return;
}
e.preventDefault();
@@ -92,8 +88,10 @@ const StandardUserInterfaceBase: React.FC =
return () => {
window.removeEventListener("resize", resizeListener, false);
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
useEffect(resizeListener, [props.minimumLargeScreenWidth]);
useEffect(() => {
@@ -118,6 +116,7 @@ const StandardUserInterfaceBase: React.FC =
width: 300
});
}
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.terria.storyPromptShown]);
// Merge theme in order of highest priority: themeOverrides props -> theme config parameter -> default terriaTheme
@@ -133,8 +132,6 @@ const StandardUserInterfaceBase: React.FC =
props.children
);
- const terria = props.terria;
-
const showStoryBuilder =
props.viewState.storyBuilderShown &&
!props.viewState.useSmallScreenInterface;
@@ -226,7 +223,6 @@ const StandardUserInterfaceBase: React.FC =
diff --git a/lib/ReactViews/StandardUserInterface/processCustomElements.d.ts b/lib/ReactViews/StandardUserInterface/processCustomElements.d.ts
new file mode 100644
index 00000000000..24f4b3d9edb
--- /dev/null
+++ b/lib/ReactViews/StandardUserInterface/processCustomElements.d.ts
@@ -0,0 +1,15 @@
+import React from "react";
+
+type GroupElementKeys =
+ | "menu"
+ | "menuLeft"
+ | "nav"
+ | "experimentalMenu"
+ | "feedback";
+
+declare function processCustomElements(
+ isSmallScreen: boolean,
+ customUI: React.ReactNode
+): Record;
+
+export default processCustomElements;
diff --git a/lib/ReactViews/StandardUserInterface/standard-user-interface.scss b/lib/ReactViews/StandardUserInterface/standard-user-interface.scss
index e8c8a154c58..60a491ec911 100644
--- a/lib/ReactViews/StandardUserInterface/standard-user-interface.scss
+++ b/lib/ReactViews/StandardUserInterface/standard-user-interface.scss
@@ -40,15 +40,15 @@
.ui-root {
// This is a workaround for a bug in IE11 on Windows 7.
// https://connect.microsoft.com/IE/feedback/details/796745/mouse-events-are-not-delivered-at-all-anymore-when-inside-an-svg-a-use-is-removed-from-the-dom
- svg use {
- pointer-events: none;
- }
position: relative;
flex-basis: 100%;
height: 100vh;
@media (max-width: $sm) {
position: unset;
}
+ svg use {
+ pointer-events: none;
+ }
}
.ui {
@@ -153,8 +153,6 @@
}
@media (min-width: $sm) {
- .ui {
- }
.uiInner {
display: flex;
overflow: hidden;
diff --git a/lib/ReactViews/Story/Story.tsx b/lib/ReactViews/Story/Story.tsx
index ca2d54c2980..1d48e90f6a9 100644
--- a/lib/ReactViews/Story/Story.tsx
+++ b/lib/ReactViews/Story/Story.tsx
@@ -1,6 +1,10 @@
import classNames from "classnames";
-import { TFunction } from "i18next";
-import React, { MouseEventHandler, useEffect, useRef } from "react";
+import React, {
+ MouseEventHandler,
+ useEffect,
+ useLayoutEffect,
+ useRef
+} from "react";
import { sortable } from "react-anything-sortable";
import { useTranslation } from "react-i18next";
import styled, { useTheme } from "styled-components";
@@ -39,7 +43,7 @@ interface Props {
}
interface MenuProps extends Props {
- t: TFunction;
+ storyRef: React.RefObject;
}
const findTextContent = (content: any): string => {
@@ -144,70 +148,87 @@ const recaptureStory =
hideList(props);
};
-const calculateOffset =
- (props: Props) => (storyRef: React.RefObject) => {
- const offsetTop = storyRef.current?.offsetTop || 0;
- const scrollTop = props.parentRef.current.scrollTop || 0;
- const heightParent =
- (storyRef.current?.offsetParent as HTMLElement)?.offsetHeight || 0;
+const StoryMenu = (props: MenuProps) => {
+ const { t } = useTranslation();
+ const menuRef = useRef(null);
+ useLayoutEffect(() => {
+ // Adjust the position of the menu so it stays inside the scroll container.
- const offsetTopScroll = offsetTop - scrollTop + 25;
- if (offsetTopScroll + 125 > heightParent) {
- return `bottom ${offsetTopScroll + 125 - heightParent + 45}px;`;
- }
- return `top: ${offsetTopScroll}px;`;
- };
+ if (!menuRef.current) return;
+ if (!props.parentRef.current) return;
-const renderMenu = (props: MenuProps) => {
- const { t } = props;
+ // Grow downwards, by default:
+ Object.assign(menuRef.current.style, { top: "0px", bottom: "unset" });
+ const selfRect = menuRef.current.getBoundingClientRect();
+ const parentRect = props.parentRef.current.getBoundingClientRect();
+ if (selfRect.bottom > parentRect.bottom) {
+ // Looks like there's no room to the bottom; grow upwards.
+ Object.assign(menuRef.current.style, { top: "unset", bottom: "0px" });
+ }
+ }, [props.parentRef]);
return (
-
-
-
-
-
- {t("story.view")}
-
-
-
-
-
-
-
- {t("story.edit")}
-
-
-
-
-
-
-
- {t("story.recapture")}
-
-
-
-
-
-
-
- {t("story.delete")}
-
-
-
-
+
+
+
+
+
+
+ {t("story.view")}
+
+
+
+
+
+
+
+ {t("story.edit")}
+
+
+
+
+
+
+
+ {t("story.recapture")}
+
+
+
+
+
+
+
+ {t("story.delete")}
+
+
+
+
+
);
};
@@ -237,7 +258,6 @@ const Story = (props: Props) => {
cursor: move;
float: none !important;
`}
- position="static"
style={props.style}
className={classNames(props.className)}
onMouseDown={props.onMouseDown}
@@ -245,7 +265,6 @@ const Story = (props: Props) => {
>
{
/>
- {props.menuOpen && (
-
- {renderMenu({ ...props, t })}
-
- )}
+ {props.menuOpen && }
{bodyText.length > 0 && (
diff --git a/lib/ReactViews/Story/StoryBuilder.tsx b/lib/ReactViews/Story/StoryBuilder.tsx
index 4907ceb1b69..a42b7255099 100644
--- a/lib/ReactViews/Story/StoryBuilder.tsx
+++ b/lib/ReactViews/Story/StoryBuilder.tsx
@@ -30,12 +30,12 @@ import SharePanel from "../Map/Panels/SharePanel/SharePanel";
import { WithViewState, withViewState } from "../Context";
import Story from "./Story";
import Styles from "./story-builder.scss";
-import StoryEditor from "./StoryEditor.jsx";
+import StoryEditor from "./StoryEditor";
const dataStoriesImg = require("../../../wwwroot/images/data-stories-getting-started.jpg");
const STORY_VIDEO = "storyVideo";
-type StoryData = ViewState["terria"]["stories"][number];
+export type StoryData = ViewState["terria"]["stories"][number];
interface IProps {
isVisible?: boolean;
@@ -85,7 +85,7 @@ class StoryBuilder extends React.Component<
storyWithOpenMenuId: undefined
};
}
- removeStory = (index: number, story: StoryData) => {
+ removeStory = (index: number, story?: StoryData) => {
this.setState({
isSharing: false,
isRemoving: true,
@@ -293,13 +293,13 @@ class StoryBuilder extends React.Component<
});
};
- renderPlayShare(hasStories: boolean | undefined) {
+ renderPlayShare() {
const { t } = this.props;
return (
+ <>
-
+
{this.state.isRemoving && (
}
css={`
margin-right: -10px;
@@ -404,7 +403,6 @@ class StoryBuilder extends React.Component<
direction="vertical"
dynamic
css={`
- position: static;
margin-right: 10px;
`}
>
@@ -433,10 +431,10 @@ class StoryBuilder extends React.Component<
disabled={this.state.isRemoving}
onClickCapture={this.onClickCapture}
/>
+
-
-
+ >
);
}
@@ -465,8 +463,6 @@ class StoryBuilder extends React.Component<
ref={(component: HTMLElement) => (this.refToMeasure = component)}
isVisible={this.props.isVisible}
isHidden={!this.props.isVisible}
- styledWidth={"320px"}
- styledMinWidth={"320px"}
charcoalGreyBg
column
>
@@ -495,10 +491,10 @@ class StoryBuilder extends React.Component<
{!hasStories && this.renderIntro()}
- {hasStories && this.renderPlayShare(hasStories)}
+ {hasStories && this.renderPlayShare()}
- {hasStories && this.renderStories(this.state.editingMode)}
+ {hasStories && this.renderStories()}
{this.state.editingMode && (
& {
const Panel = styled(Box)`
transition: all 0.25s;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ width: 320px;
+ min-width: 320px;
+ height: 100vh;
${(props) =>
props.isVisible &&
`
@@ -531,7 +530,7 @@ const Panel = styled(Box)`
props.isHidden &&
`
visibility: hidden;
- margin-right: -${props.styledWidth ? props.styledWidth : "320px"};
+ margin-right: -100%;
`}
`;
diff --git a/lib/ReactViews/Story/StoryEditor.d.ts b/lib/ReactViews/Story/StoryEditor.d.ts
new file mode 100644
index 00000000000..3bf04fdcc2a
--- /dev/null
+++ b/lib/ReactViews/Story/StoryEditor.d.ts
@@ -0,0 +1,15 @@
+import React from "react";
+import Terria from "../../Models/Terria";
+import { StoryData } from "./StoryBuilder";
+
+interface PropsType {
+ story?: StoryData;
+ removeStory: (id: number) => void;
+ saveStory: (story: StoryData) => void;
+ exitEditingMode: () => void;
+ terria: Terria;
+}
+
+declare class StoryEditor extends React.Component {}
+
+export default StoryEditor;
diff --git a/lib/ReactViews/Story/StoryEditor.jsx b/lib/ReactViews/Story/StoryEditor.jsx
index a4601881125..aa001952d7b 100644
--- a/lib/ReactViews/Story/StoryEditor.jsx
+++ b/lib/ReactViews/Story/StoryEditor.jsx
@@ -136,7 +136,14 @@ class StoryEditor extends React.Component {
this.setState({ text: value });
}
- renderPopupEditor() {
+ removeStory() {
+ this.props.exitEditingMode();
+ if (this.state.id) {
+ this.props.removeStory(this.state.id);
+ }
+ }
+
+ render() {
const { t } = this.props;
const maxImageHeight = "350px"; // TODO: where to put this to reduce coupling?
return (
@@ -198,17 +205,6 @@ class StoryEditor extends React.Component {
);
}
-
- removeStory() {
- this.props.exitEditingMode();
- if (this.state.id) {
- this.props.removeStory(this.state.id);
- }
- }
-
- render() {
- return {this.renderPopupEditor()}
;
- }
}
StoryEditor.propTypes = {
diff --git a/lib/ReactViews/Story/story-editor.scss b/lib/ReactViews/Story/story-editor.scss
index 7d166eae92b..4d29155f8a7 100644
--- a/lib/ReactViews/Story/story-editor.scss
+++ b/lib/ReactViews/Story/story-editor.scss
@@ -2,10 +2,6 @@
@import "../../Sass/common/mixins";
.popupEditor {
- &.is-mounted {
- opacity: 1;
- @include transform(none);
- }
@include transform(translateY(20%));
opacity: 0;
@include transition(all 0.3s);
@@ -19,6 +15,10 @@
display: flex;
flex-direction: column;
justify-content: center;
+ &.is-mounted {
+ opacity: 1;
+ @include transform(none);
+ }
.inner {
max-width: 800px;
width: 80vw;
@@ -44,21 +44,6 @@
}
}
-.editor {
- background: $dark-with-overlay;
- color: $text-light;
- font-family: $font-pop;
- margin: $padding-small;
- border-radius: 4px;
- .editorHeader {
- padding: $padding;
- border-bottom: 1px solid $overlay;
- }
- form {
- padding: $padding;
- }
-}
-
.field {
composes: field from "../../Sass/common/_form.scss";
border: 0;
@@ -66,24 +51,9 @@
padding: 0 !important;
}
-.fieldBtn {
- composes: btn from "../../Sass/common/_buttons.scss";
- composes: btn--map from "../../Sass/common/_buttons.scss";
- background: #9ca1aa;
- border-radius: 4px;
- padding: $padding;
- margin-bottom: $padding + 3px;
- box-shadow: none;
- width: 100%;
-}
-
-.doneBtn,
.saveBtn {
composes: btn from "../../Sass/common/_buttons.scss";
composes: btn-primary from "../../Sass/common/_buttons.scss";
-}
-
-.saveBtn {
width: auto;
padding: 5px 15px;
}
diff --git a/lib/ReactViews/Story/story-editor.scss.d.ts b/lib/ReactViews/Story/story-editor.scss.d.ts
index ccb456e9f56..5f8d5b648f9 100644
--- a/lib/ReactViews/Story/story-editor.scss.d.ts
+++ b/lib/ReactViews/Story/story-editor.scss.d.ts
@@ -3,11 +3,7 @@
interface CssExports {
'body': string;
'cancelBtn': string;
- 'doneBtn': string;
- 'editor': string;
- 'editorHeader': string;
'field': string;
- 'fieldBtn': string;
'header': string;
'inner': string;
'is-mounted': string;
diff --git a/lib/ReactViews/Story/story-panel.scss b/lib/ReactViews/Story/story-panel.scss
index 3e922791415..4cc2b38dad1 100644
--- a/lib/ReactViews/Story/story-panel.scss
+++ b/lib/ReactViews/Story/story-panel.scss
@@ -2,10 +2,6 @@
@import "../../Sass/common/mixins";
.story-container {
- &.is-mounted {
- opacity: 1;
- @include transform(none);
- }
@include transform(translateY(20%));
opacity: 0;
@include transition(all 0.3s);
@@ -20,6 +16,11 @@
box-sizing: border-box;
box-shadow: 0 0 15px 6px rgba(100, 100, 100, 0.3);
+ &.is-mounted {
+ opacity: 1;
+ @include transform(none);
+ }
+
.left {
border-right: 1px solid $field-border;
}
diff --git a/lib/ReactViews/Tools/ClippingBox/ClippingBoxToolLauncher.tsx b/lib/ReactViews/Tools/ClippingBox/ClippingBoxToolLauncher.tsx
index 0cf499a6e04..8b7a83977bd 100644
--- a/lib/ReactViews/Tools/ClippingBox/ClippingBoxToolLauncher.tsx
+++ b/lib/ReactViews/Tools/ClippingBox/ClippingBoxToolLauncher.tsx
@@ -46,6 +46,7 @@ const ClippingBoxToolLauncher: React.FC = observer(
}
});
},
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[item, cesium]
);
diff --git a/lib/ReactViews/Tools/ClippingBox/RepositionClippingBox.tsx b/lib/ReactViews/Tools/ClippingBox/RepositionClippingBox.tsx
index d67f5162bb7..98749c3b1fd 100644
--- a/lib/ReactViews/Tools/ClippingBox/RepositionClippingBox.tsx
+++ b/lib/ReactViews/Tools/ClippingBox/RepositionClippingBox.tsx
@@ -119,6 +119,7 @@ const RepositionClippingBox: React.FC = observer(
};
// Init effect that sets up the event handlers etc.
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
useEffect(
action(function init() {
const canvas = cesium.scene.canvas;
@@ -206,10 +207,6 @@ function setCursor(el: HTMLElement, cursorName: string) {
el.style.cursor = cursorName;
}
-function truncate(text: string, length: number) {
- return text.length <= length ? text : `${text.slice(0, length)}...`;
-}
-
function pickGlobePosition(
screenCoords: Cartesian2,
scene: Scene,
diff --git a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx
index 4422e018fac..cddffb0d93e 100644
--- a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx
+++ b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx
@@ -52,6 +52,7 @@ import Loader from "../../Loader";
import DatePicker from "./DatePicker";
import LocationPicker from "./LocationPicker";
import { CLOSE_TOOL_ID } from "../../Map/MapNavigation/registerMapNavigations";
+import updateModelFromJson from "../../../Models/Definition/updateModelFromJson";
const dateFormat = require("dateformat");
@@ -355,7 +356,7 @@ class Main extends React.Component {
}
@action.bound
- onUserPickingLocation(pickingLocation: LatLonHeight) {
+ onUserPickingLocation(_pickingLocation: LatLonHeight) {
this._isPickingNewLocation = true;
}
@@ -364,7 +365,7 @@ class Main extends React.Component {
pickedFeatures: PickedFeatures,
pickedLocation: LatLonHeight
) {
- const { leftItem, rightItem, t } = this.props;
+ const { leftItem, rightItem } = this.props;
const feature = pickedFeatures.features.find(
(f) =>
doesFeatureBelongToItem(f, leftItem) ||
@@ -404,10 +405,17 @@ class Main extends React.Component {
const terria = this.props.terria;
terria.overlays.remove(this.props.leftItem);
terria.overlays.remove(this.props.rightItem);
+
terria.workbench.add(this.diffItem);
this.diffItem.setTrait(CommonStrata.user, "name", this.diffItemName);
this.diffItem.showDiffImage(this.leftDate, this.rightDate, this.diffStyle);
+
+ // If given, appply additional properties for the diff item
+ const diffItemProperties = this.diffItem.diffItemProperties;
+ if (diffItemProperties) {
+ updateModelFromJson(this.diffItem, CommonStrata.user, diffItemProperties);
+ }
terria.showSplitter = false;
}
@@ -877,6 +885,7 @@ const AreaFilterSelection = (props: {
t: TFunction;
location?: LatLonHeight;
isPickingNewLocation: boolean;
+ theme?: any;
}) => {
const { t, location, isPickingNewLocation } = props;
let locationText = "-";
@@ -959,10 +968,8 @@ const LegendImage = function (props: any) {
{...props}
// Show the legend only if it loads successfully, so we start out hidden
style={{ display: "none", marginTop: "4px" }}
- // @ts-expect-error
- onLoad={(e) => (e.target.style.display = "block")}
- // @ts-expect-error
- onError={(e) => (e.target.style.display = "none")}
+ onLoad={(e) => (e.currentTarget.style.display = "block")}
+ onError={(e) => (e.currentTarget.style.display = "none")}
/>
);
};
@@ -993,6 +1000,13 @@ async function createSplitItem(
newItem.setTrait(CommonStrata.user, "opacity", 0);
}
+ // Override feature info template as the parent featureInfoTemplate might
+ // not be relevant for the difference item. This has to be done in the user
+ // stratum to override template set in definition stratum.
+ updateModelFromJson(newItem, CommonStrata.user, {
+ featureInfoTemplate: { template: "" }
+ });
+
setDefaultDiffStyle(newItem);
// Set the default style to true color style if it exists
diff --git a/lib/ReactViews/Tools/ItemSearchTool/ItemSearchTool.tsx b/lib/ReactViews/Tools/ItemSearchTool/ItemSearchTool.tsx
index 7cf2b4cb760..49381be5dfa 100644
--- a/lib/ReactViews/Tools/ItemSearchTool/ItemSearchTool.tsx
+++ b/lib/ReactViews/Tools/ItemSearchTool/ItemSearchTool.tsx
@@ -66,6 +66,7 @@ const ItemSearchTool: React.FC = observer((props) => {
})
.finally(() => props.afterLoad?.());
},
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[itemSearchProvider]
);
@@ -78,6 +79,7 @@ const ItemSearchTool: React.FC = observer((props) => {
);
return disposeListener;
},
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
[item]
);
diff --git a/lib/ReactViews/Tools/ItemSearchTool/SearchForm.tsx b/lib/ReactViews/Tools/ItemSearchTool/SearchForm.tsx
index a86ff8f2081..fa521862d23 100644
--- a/lib/ReactViews/Tools/ItemSearchTool/SearchForm.tsx
+++ b/lib/ReactViews/Tools/ItemSearchTool/SearchForm.tsx
@@ -306,7 +306,8 @@ const Field = styled(Box).attrs({
})``;
const ParameterName = styled(Text).attrs({
- semiBold: true
+ semiBold: true,
+ breakWord: true
})``;
const Label = styled.label``;
diff --git a/lib/ReactViews/Tools/PedestrianMode/MiniMap.tsx b/lib/ReactViews/Tools/PedestrianMode/MiniMap.tsx
index 40b1fd23dfe..de45180644c 100644
--- a/lib/ReactViews/Tools/PedestrianMode/MiniMap.tsx
+++ b/lib/ReactViews/Tools/PedestrianMode/MiniMap.tsx
@@ -35,6 +35,7 @@ const MiniMap: React.FC = (props) => {
>();
const [locationMarker, setLocationMarker] = useState();
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
useEffect(
action(() => {
const marker = new Marker(
diff --git a/lib/ReactViews/Tools/PedestrianMode/MovementControls.tsx b/lib/ReactViews/Tools/PedestrianMode/MovementControls.tsx
index 97114e22fa9..e66dc654a6f 100644
--- a/lib/ReactViews/Tools/PedestrianMode/MovementControls.tsx
+++ b/lib/ReactViews/Tools/PedestrianMode/MovementControls.tsx
@@ -35,6 +35,7 @@ const MovementControls: React.FC = (props) => {
);
const detach = movementsController.activate();
return detach;
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.cesium]);
return (
@@ -75,10 +76,10 @@ const Title = styled(Box).attrs({
border-bottom: 1px solid #c0c0c0;
`;
-const MinimizeMaximizeButton = styled(Button).attrs((props) => ({
+const MinimizeMaximizeButton = styled(Button).attrs(({ maximized }) => ({
renderIcon: () => (
)
}))<{ maximized: boolean }>`
diff --git a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx
index 5d020221363..1f2eb5a918e 100644
--- a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx
+++ b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx
@@ -47,6 +47,7 @@ const PedestrianMode: React.FC = observer((props) => {
return () => {
viewState.terria.mapNavigationModel.enable(MeasureTool.id);
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
useEffect(function closeOnZoomTo() {
@@ -56,6 +57,7 @@ const PedestrianMode: React.FC = observer((props) => {
if (isMapZooming) viewState.closeTool();
}
);
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
return (
diff --git a/lib/ReactViews/Tools/ToolModal.tsx b/lib/ReactViews/Tools/ToolModal.tsx
index 1a74fae8486..1eda6275bf1 100644
--- a/lib/ReactViews/Tools/ToolModal.tsx
+++ b/lib/ReactViews/Tools/ToolModal.tsx
@@ -52,6 +52,9 @@ export const Frame: React.FC = observer((props) => {
);
});
+const TOP_MARGIN = 70;
+const BOTTOM_MARGIN = 100;
+
export const Main = styled(Text)`
display: flex;
flex-direction: column;
@@ -68,9 +71,10 @@ const Wrapper = styled(Box).attrs({
styledWidth: "340px"
// charcoalGreyBg: true
})<{ isMapFullScreen: boolean }>`
- top: 70px;
+ top: ${TOP_MARGIN}px;
left: 0px;
min-height: 220px;
+ max-height: calc(100vh - ${TOP_MARGIN + BOTTOM_MARGIN}px);
// background: ${(p) => p.theme.dark};
margin-left: ${(props) =>
props.isMapFullScreen
diff --git a/lib/ReactViews/Tour/TourPortal.d.ts b/lib/ReactViews/Tour/TourPortal.d.ts
new file mode 100644
index 00000000000..82d9ed2b400
--- /dev/null
+++ b/lib/ReactViews/Tour/TourPortal.d.ts
@@ -0,0 +1,8 @@
+import React from "react";
+
+export declare const TourExplanation: React.FC;
+export declare const TourPreface: React.FC;
+
+declare const TourPortal: React.FC<{}>;
+
+export default TourPortal;
diff --git a/lib/ReactViews/Tour/tour-helpers.ts b/lib/ReactViews/Tour/tour-helpers.ts
index 8de3185b18a..253c3def15b 100644
--- a/lib/ReactViews/Tour/tour-helpers.ts
+++ b/lib/ReactViews/Tour/tour-helpers.ts
@@ -2,10 +2,7 @@
import { TourPoint } from "../../ReactViewModels/defaultTourPoints";
import isDefined from "../../Core/isDefined";
-import {
- RelativePosition,
- TOUR_WIDTH
-} from "../../ReactViewModels/defaultTourPoints";
+import { RelativePosition } from "../../ReactViewModels/defaultTourPoints";
export {
RelativePosition,
TOUR_WIDTH
diff --git a/lib/ReactViews/Transitions/FadeIn/FadeIn.d.ts b/lib/ReactViews/Transitions/FadeIn/FadeIn.d.ts
new file mode 100644
index 00000000000..e1e12a556b4
--- /dev/null
+++ b/lib/ReactViews/Transitions/FadeIn/FadeIn.d.ts
@@ -0,0 +1,11 @@
+import React from "react";
+
+interface PropsType {
+ isVisible: boolean;
+ onEnter?: () => void;
+ onExited?: () => void;
+ transitionProps?: any;
+}
+
+declare const FadeIn: React.FC;
+export default FadeIn;
diff --git a/lib/ReactViews/Transitions/SlideUpFadeIn/SlideUpFadeIn.d.ts b/lib/ReactViews/Transitions/SlideUpFadeIn/SlideUpFadeIn.d.ts
new file mode 100644
index 00000000000..24fd61b8fa0
--- /dev/null
+++ b/lib/ReactViews/Transitions/SlideUpFadeIn/SlideUpFadeIn.d.ts
@@ -0,0 +1,11 @@
+import React from "react";
+
+interface PropsType {
+ isVisible: boolean;
+ onEnter?: () => void;
+ onExited?: () => void;
+ transitionProps?: any;
+}
+
+declare const SlideUpFadeIn: React.FC;
+export default SlideUpFadeIn;
diff --git a/lib/ReactViews/WelcomeMessage/WelcomeMessage.d.ts b/lib/ReactViews/WelcomeMessage/WelcomeMessage.d.ts
new file mode 100644
index 00000000000..858b3816356
--- /dev/null
+++ b/lib/ReactViews/WelcomeMessage/WelcomeMessage.d.ts
@@ -0,0 +1,12 @@
+import React from "react";
+
+interface WelcomeMessagePurePropsType {
+ showWelcomeMessage: boolean;
+ setShowWelcomeMessage: (show: boolean) => void;
+ isTopElement: boolean;
+}
+
+export declare const WelcomeMessagePure: React.FC;
+
+declare class WelcomeMessage extends React.Component<{}> {}
+export default WelcomeMessage;
diff --git a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx
index 1df80969196..dc74e1dc486 100644
--- a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx
+++ b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx
@@ -262,7 +262,7 @@ export const WelcomeMessagePure = (props) => {
viewState.terria.configParameters.welcomeMessageVideo
.placeholderImage
}
- backgroundBlackOverlay={"50%"}
+ backgroundBlackOverlay={0.5}
>
{}
+export default ColorScaleRangeSection;
diff --git a/lib/ReactViews/Workbench/Controls/DisplayAsPercentSection.tsx b/lib/ReactViews/Workbench/Controls/DisplayAsPercentSection.tsx
index 2d28defaa60..b2b9bb7dc63 100644
--- a/lib/ReactViews/Workbench/Controls/DisplayAsPercentSection.tsx
+++ b/lib/ReactViews/Workbench/Controls/DisplayAsPercentSection.tsx
@@ -13,7 +13,7 @@ const DisplayAsPercentSection: React.FC = (
props: IDisplayAsPercentSection
) => {
const { t } = useTranslation();
- const theme = useTheme();
+ useTheme();
const togglePercentage = () => {
props.item.displayPercent = !props.item.displayPercent;
};
diff --git a/lib/ReactViews/Workbench/Controls/FilterSection.d.ts b/lib/ReactViews/Workbench/Controls/FilterSection.d.ts
new file mode 100644
index 00000000000..b599403cb16
--- /dev/null
+++ b/lib/ReactViews/Workbench/Controls/FilterSection.d.ts
@@ -0,0 +1,9 @@
+import React from "react";
+import { BaseModel } from "../../../Models/Definition/Model";
+
+interface PropsType {
+ item: BaseModel;
+}
+
+declare class FilterSection extends React.Component {}
+export default FilterSection;
diff --git a/lib/ReactViews/Workbench/Controls/FilterSection.jsx b/lib/ReactViews/Workbench/Controls/FilterSection.jsx
index 14cabf8452c..634a2acb4b2 100644
--- a/lib/ReactViews/Workbench/Controls/FilterSection.jsx
+++ b/lib/ReactViews/Workbench/Controls/FilterSection.jsx
@@ -27,7 +27,7 @@ class FilterSection extends React.Component {
}
return (
- {item.filters.map(this.renderFilter)}
+ {item.filters.map(this.renderFilter, this)}
);
}
diff --git a/lib/ReactViews/Workbench/Controls/SatelliteImageryTimeFilterSection.d.ts b/lib/ReactViews/Workbench/Controls/SatelliteImageryTimeFilterSection.d.ts
new file mode 100644
index 00000000000..35be383dbda
--- /dev/null
+++ b/lib/ReactViews/Workbench/Controls/SatelliteImageryTimeFilterSection.d.ts
@@ -0,0 +1,9 @@
+import React from "react";
+import { BaseModel } from "../../../Models/Definition/Model";
+
+interface PropsType {
+ item: BaseModel;
+}
+
+declare class SatelliteImageryTimeFilterSection extends React.Component {}
+export default SatelliteImageryTimeFilterSection;
diff --git a/lib/ReactViews/Workbench/Controls/ShortReport.tsx b/lib/ReactViews/Workbench/Controls/ShortReport.tsx
index 7143a9eac89..de5dac79e52 100644
--- a/lib/ReactViews/Workbench/Controls/ShortReport.tsx
+++ b/lib/ReactViews/Workbench/Controls/ShortReport.tsx
@@ -1,5 +1,3 @@
-"use strict";
-
import { runInAction } from "mobx";
import { observer } from "mobx-react";
import React from "react";
@@ -103,5 +101,3 @@ export default class ShortReport extends React.Component<{
);
}
}
-
-module.exports = ShortReport;
diff --git a/lib/ReactViews/Workbench/Controls/TimerSection.d.ts b/lib/ReactViews/Workbench/Controls/TimerSection.d.ts
new file mode 100644
index 00000000000..1ae97eb7525
--- /dev/null
+++ b/lib/ReactViews/Workbench/Controls/TimerSection.d.ts
@@ -0,0 +1,5 @@
+import React from "react";
+import { BaseModel } from "../../../Models/Definition/Model";
+
+declare class TimerSection extends React.Component<{ item: BaseModel }> {}
+export default TimerSection;
diff --git a/lib/ReactViews/Workbench/Controls/legend.scss b/lib/ReactViews/Workbench/Controls/legend.scss
index 2d80290343c..6896f67a87f 100644
--- a/lib/ReactViews/Workbench/Controls/legend.scss
+++ b/lib/ReactViews/Workbench/Controls/legend.scss
@@ -4,15 +4,13 @@
composes: clearfix from "../../../Sass/common/_base.scss";
composes: list-reset from "../../../Sass/common/_base.scss";
font-family: $font-mono;
- font-size: $font-size-small;
+ // Small font size prevents the font from dictating the table row height.
+ font-size: 5px;
li {
display: block;
}
- // Small font size prevents the font from dictating the table row height.
- font-size: 5px;
-
.legendOpenExternally {
font-size: $font-size-small;
color: $text-light;
@@ -25,11 +23,11 @@
}
.legend__inner {
+ padding: $padding 0 0 0;
a {
// Only the actual legend should be clickable rather than the whole area
display: inline-block;
}
- padding: $padding 0 0 0;
}
.legend__legendBoxImg {
diff --git a/lib/ReactViews/Workflow/WorkflowPanel.tsx b/lib/ReactViews/Workflow/WorkflowPanel.tsx
index 6eff618dffa..fcc104092c1 100644
--- a/lib/ReactViews/Workflow/WorkflowPanel.tsx
+++ b/lib/ReactViews/Workflow/WorkflowPanel.tsx
@@ -37,6 +37,7 @@ const WorkflowPanel: React.FC = observer((props) => {
viewState.terria.isWorkflowPanelActive = false;
});
};
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
return (
@@ -72,6 +73,7 @@ const WorkflowPanel: React.FC = observer((props) => {
type ErrorBoundaryProps = {
viewState: ViewState;
+ children: React.ReactNode;
};
class ErrorBoundary extends React.Component {
@@ -118,10 +120,6 @@ const TitleBar = styled.div`
border-bottom: 1px solid ${(p) => p.theme.darkLighter};
`;
-const FooterBar = styled(TitleBar)`
- border: none;
-`;
-
const Title = styled(Text).attrs({
textLight: true,
bold: true
diff --git a/lib/Sass/common/_base.scss b/lib/Sass/common/_base.scss
index 3ba9c9e415e..9d83ff804bc 100644
--- a/lib/Sass/common/_base.scss
+++ b/lib/Sass/common/_base.scss
@@ -429,6 +429,16 @@
// This is what happens when we mess up with CSS Modules so make it SUPER SUPER OBVIOUS
// TODO: Remove in build
.undefined {
+ position: relative;
+ background: #f00 !important;
+ color: magenta !important;
+ border: 3px orange dashed !important;
+
+ animation-name: flash;
+ animation-duration: 1s;
+ animation-timing-function: step-start;
+ animation-iteration-count: infinite;
+
&:before {
position: fixed !important;
top: 0 !important;
@@ -439,16 +449,6 @@
opacity: 1 !important;
z-index: 100000 !important;
}
-
- position: relative;
- background: #f00 !important;
- color: magenta !important;
- border: 3px orange dashed !important;
-
- animation-name: flash;
- animation-duration: 1s;
- animation-timing-function: step-start;
- animation-iteration-count: infinite;
}
@keyframes flash {
diff --git a/lib/Sass/common/_buttons.scss b/lib/Sass/common/_buttons.scss
index ccf7bfd0599..84684c7bfa7 100644
--- a/lib/Sass/common/_buttons.scss
+++ b/lib/Sass/common/_buttons.scss
@@ -153,23 +153,22 @@ $btn-setting-size: 35px;
.btn--catalog {
padding: $padding 30px + $padding;
- @media (min-width: $sm) {
- padding: $padding-small 30px + $padding;
- }
-
position: relative;
width: 100%;
font-weight: bold;
+ @media (min-width: $sm) {
+ padding: $padding-small 30px + $padding;
+ }
.btn--group-indicator {
position: absolute;
left: 0;
padding: $padding $padding * 2.2 $padding $padding * 1.5;
- @media (min-width: $sm) {
- padding: $padding-small $padding * 2.2 $padding-small $padding * 1.5;
- }
top: 0;
font-size: $font-size-mid-large;
opacity: 0.5;
+ @media (min-width: $sm) {
+ padding: $padding-small $padding * 2.2 $padding-small $padding * 1.5;
+ }
}
&:before {
position: absolute;
diff --git a/lib/Sass/common/_variables.scss b/lib/Sass/common/_variables.scss
index 26a01198883..25272c0ec8e 100644
--- a/lib/Sass/common/_variables.scss
+++ b/lib/Sass/common/_variables.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
@import url("https://fonts.googleapis.com/css?family=Nunito:300,400,500,400italic,600,700&display=swap");
$font-pop: "Nunito", sans-serif;
@@ -9,7 +11,7 @@ $font: $font-base;
$color-primary: #519ac2;
$color-primary-disabled: #595b60;
@function get-hover-color($base-color) {
- @return lighten($base-color, 10%);
+ @return color.adjust($base-color, $lightness: 10%);
}
$color-secondary: #ff6f00;
@@ -169,7 +171,7 @@ $chart-grid-color: rgba(#fff, 0.085);
$chart-text-color: #fff;
$chart-line-color: #ccc;
$chart-preview-line-color: $chart-line-color;
-$chart-darker: darken($dark, 8%);
+$chart-darker: color.adjust($dark, $lightness: -8%);
$chart-panel-background: $dark;
$chart-panel-header: $chart-darker;
diff --git a/lib/Styled/Box.tsx b/lib/Styled/Box.tsx
index 0811606137f..4f6a3559278 100644
--- a/lib/Styled/Box.tsx
+++ b/lib/Styled/Box.tsx
@@ -1,4 +1,4 @@
-import { Ref } from "react";
+import React, { Ref } from "react";
import styled from "styled-components";
import { Overflow, WhiteSpace, WordBreak } from "./Styled.types";
@@ -243,7 +243,7 @@ export const Box = styled.div`
`;
export const BoxSpan = styled(Box).attrs(
- (props: { as?: React.ElementType | keyof JSX.IntrinsicElements }) => ({
+ (_props: { as?: React.ElementType | keyof JSX.IntrinsicElements }) => ({
as: "span"
})
)``;
diff --git a/lib/Styled/Button.tsx b/lib/Styled/Button.tsx
index d6a362424c4..948b8066cbe 100644
--- a/lib/Styled/Button.tsx
+++ b/lib/Styled/Button.tsx
@@ -165,6 +165,10 @@ export const RawButton = styled.button`
export type ButtonProps = {
renderIcon?: () => React.ReactChild;
iconProps?: any;
+ primary?: boolean;
+ secondary?: boolean;
+ warning?: boolean;
+ textLight?: boolean;
rightIcon?: boolean;
textProps?: any;
children?: React.ReactChildren;
diff --git a/lib/Styled/Checkbox/Checkbox.tsx b/lib/Styled/Checkbox/Checkbox.tsx
index 30cc5a6078b..0c91c514107 100644
--- a/lib/Styled/Checkbox/Checkbox.tsx
+++ b/lib/Styled/Checkbox/Checkbox.tsx
@@ -14,115 +14,113 @@ import CheckboxIcon from "./Elements/CheckboxIcon";
import HiddenCheckbox from "./Elements/HiddenCheckbox";
import { ICheckboxProps } from "./types";
-const Checkbox = memo(
- forwardRef(function Checkbox(
- props: ICheckboxProps,
- ref: Ref
- ) {
- const {
- isChecked: isCheckedProp,
- isDisabled = false,
- defaultChecked = false,
- isIndeterminate = false,
- onChange: onChangeProps,
- title,
- name,
- value,
- children,
- textProps,
- className,
- ...rest
- } = props;
+const Checkbox = forwardRef(function Checkbox(
+ props: ICheckboxProps,
+ ref: Ref
+) {
+ const {
+ isChecked: isCheckedProp,
+ isDisabled = false,
+ defaultChecked = false,
+ isIndeterminate = false,
+ onChange: onChangeProps,
+ title,
+ name,
+ value,
+ children,
+ textProps,
+ className,
+ ..._rest
+ } = props;
- const [isCheckedState, setIsCheckedState] = useState(
- isCheckedProp !== undefined ? isCheckedProp : defaultChecked
- );
+ const [isCheckedState, setIsCheckedState] = useState(
+ isCheckedProp !== undefined ? isCheckedProp : defaultChecked
+ );
- const onChange = useCallback(
- (e: ChangeEvent) => {
- setIsCheckedState(e.target.checked);
- if (onChangeProps) {
- onChangeProps(e);
- }
- },
- [onChangeProps]
- );
+ const onChange = useCallback(
+ (e: ChangeEvent) => {
+ setIsCheckedState(e.target.checked);
+ if (onChangeProps) {
+ onChangeProps(e);
+ }
+ },
+ [onChangeProps]
+ );
- // Use isChecked from the state if it is controlled
- const isChecked =
- isCheckedProp === undefined ? isCheckedState : isCheckedProp;
- const id = useUID();
+ // Use isChecked from the state if it is controlled
+ const isChecked =
+ isCheckedProp === undefined ? isCheckedState : isCheckedProp;
+ const id = useUID();
- // Add props to children
- const childrenWithProps = React.Children.map(children, (child) => {
- // Checking isValidElement is the safe way and avoids a typescript
- // error too.
- if (React.isValidElement(child)) {
- return React.cloneElement(
- child as ReactElement<{
- isDisabled: boolean;
- isChecked: boolean;
- style: any;
- }>,
- {
- isDisabled,
- isChecked,
- style: { fontSize: "inherit" }
- }
- );
- }
- return child;
- });
+ // Add props to children
+ const childrenWithProps = React.Children.map(children, (child) => {
+ // Checking isValidElement is the safe way and avoids a typescript
+ // error too.
+ if (React.isValidElement(child)) {
+ return React.cloneElement(
+ child as ReactElement<{
+ isDisabled: boolean;
+ isChecked: boolean;
+ style: any;
+ }>,
+ {
+ isDisabled,
+ isChecked,
+ style: { fontSize: "inherit" }
+ }
+ );
+ }
+ return child;
+ });
- return (
-
-
-
-
- {childrenWithProps}
-
- );
- })
-);
+ `}
+ {...textProps}
+ >
+
+
+
+ {childrenWithProps}
+
+ );
+});
Checkbox.displayName = "Checkbox";
-export default Checkbox;
+export default memo(Checkbox);
diff --git a/lib/Styled/Input.tsx b/lib/Styled/Input.tsx
index af39408e4a0..86653d714cd 100644
--- a/lib/Styled/Input.tsx
+++ b/lib/Styled/Input.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import styled, { css, DefaultTheme, useTheme } from "styled-components";
+import styled, { css, useTheme } from "styled-components";
import Box, { IBoxProps } from "./Box";
export interface CommonProps {
@@ -126,7 +126,7 @@ export const StyledInput = styled.input`
const Input: React.FC = (props: InputProps) => {
const { boxProps, ...rest }: InputProps = props;
- const theme: DefaultTheme = useTheme();
+ useTheme();
return (
diff --git a/lib/Styled/Text.tsx b/lib/Styled/Text.tsx
index 73819e0ad4d..1f9b92a52c6 100644
--- a/lib/Styled/Text.tsx
+++ b/lib/Styled/Text.tsx
@@ -1,4 +1,4 @@
-import { ComponentProps } from "react";
+import React, { ComponentProps } from "react";
import styled from "styled-components";
interface ITextSize {
diff --git a/lib/Styled/mixins.js b/lib/Styled/mixins.ts
similarity index 81%
rename from lib/Styled/mixins.js
rename to lib/Styled/mixins.ts
index ec3e61403f9..359691550c6 100644
--- a/lib/Styled/mixins.js
+++ b/lib/Styled/mixins.ts
@@ -1,5 +1,11 @@
// Doesn't result in composed classes that reuse these, but to save some typing
+import cssExports from "../Sass/exports/_variables-export.scss";
+
+interface MixinProps {
+ theme: typeof cssExports;
+}
+
export const scrollBars = () => `
-webkit-overflow-scrolling: touch;
@@ -41,16 +47,16 @@ export const removeListStyles = () => `
margin: 0;
`;
-export const borderRadiusTop = (radius) => `
+export const borderRadiusTop = (radius: number | string) => `
border-radius: ${radius}px ${radius}px 0 0;
`;
-export const borderRadiusRight = (radius) => `
+export const borderRadiusRight = (radius: number | string) => `
border-radius: 0 ${radius}px ${radius}px 0;
`;
-export const borderRadiusBottom = (radius) => `
+export const borderRadiusBottom = (radius: number | string) => `
border-radius: 0 0 ${radius}px ${radius}px;
`;
-export const borderRadiusLeft = (radius) => `
+export const borderRadiusLeft = (radius: number | string) => `
border-radius: ${radius}px 0 0 ${radius}px;
`;
@@ -65,7 +71,7 @@ export const addBasicHoverStyles = () => `
* unfortunately this means more classnames outputted, but gives us consistency
* in the meantime.
* */
-export const addTerriaPrimaryBtnStyles = (props) => `
+export const addTerriaPrimaryBtnStyles = (props: MixinProps) => `
background: ${props.theme.colorPrimary};
color: ${props.theme.textLight};
svg {
@@ -79,7 +85,7 @@ export const addTerriaPrimaryBtnStyles = (props) => `
}
`;
-export const addTerriaSecondaryBtnStyles = (props) => `
+export const addTerriaSecondaryBtnStyles = (props: MixinProps) => `
color: ${props.theme.colorPrimary};
// Don't override border here on secondary, as it's set specifically on certain buttons e.g. story cancel button
@@ -91,7 +97,7 @@ export const addTerriaSecondaryBtnStyles = (props) => `
${addBasicHoverStyles()}
`;
-export const addTerriaTertiaryBtnStyles = (props) => `
+export const addTerriaTertiaryBtnStyles = (props: MixinProps) => `
color: ${props.theme.modalText};
background: ${props.theme.modalBg};
border: 2px solid ${props.theme.modalText};
@@ -103,7 +109,7 @@ export const addTerriaTertiaryBtnStyles = (props) => `
}
`;
-export const addTerriaMapBtnStyles = (props) => `
+export const addTerriaMapBtnStyles = (props: MixinProps) => `
color: ${props.theme.textLight};
background-color: ${props.theme.dark};
&:hover,
@@ -123,7 +129,7 @@ export const addTerriaMapBtnStyles = (props) => `
}
`;
-export const addTerriaLightBtnStyles = (props) => `
+export const addTerriaLightBtnStyles = (props: MixinProps) => `
color: ${props.theme.textLight};
svg {
fill: ${props.theme.textLight};
@@ -135,7 +141,7 @@ export const addTerriaLightBtnStyles = (props) => `
}
`;
-export const addTerriaScrollbarStyles = (props) => `
+export const addTerriaScrollbarStyles = () => `
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
diff --git a/lib/Table/MergedStyleMapLegend.ts b/lib/Table/MergedStyleMapLegend.ts
index 4e9669c2b8b..40006a8e2ff 100644
--- a/lib/Table/MergedStyleMapLegend.ts
+++ b/lib/Table/MergedStyleMapLegend.ts
@@ -18,7 +18,7 @@ export class MergedStyleMapLegend extends LoadableStratum(LegendTraits) {
makeObservable(this);
}
- duplicateLoadableStratum(newModel: BaseModel): this {
+ duplicateLoadableStratum(_newModel: BaseModel): this {
return new MergedStyleMapLegend(this.legends) as this;
}
diff --git a/lib/Table/TableAutomaticStylesStratum.ts b/lib/Table/TableAutomaticStylesStratum.ts
index 2833b0a5298..5428237cfb4 100644
--- a/lib/Table/TableAutomaticStylesStratum.ts
+++ b/lib/Table/TableAutomaticStylesStratum.ts
@@ -231,7 +231,7 @@ export default class TableAutomaticStylesStratum extends LoadableStratum(
i < this.catalogItem.activeTableStyle.rowGroups.length;
i++
) {
- const [rowGroupId, rowIds] =
+ const [_rowGroupId, rowIds] =
this.catalogItem.activeTableStyle.rowGroups[i];
// Check if there is only 1 unique date in this rowGroup
const dates = rowIds
diff --git a/lib/Table/TableColumn.ts b/lib/Table/TableColumn.ts
index 458575fdb4c..191401d4a37 100644
--- a/lib/Table/TableColumn.ts
+++ b/lib/Table/TableColumn.ts
@@ -786,35 +786,6 @@ export default class TableColumn {
return this.values;
}
- @computed
- get scaledValueFunctionForType(): (rowIndex: number) => number | null {
- if (this.type === TableColumnType.scalar) {
- const valuesAsNumbers = this.valuesAsNumbers;
- const minimum = valuesAsNumbers.minimum;
- const maximum = valuesAsNumbers.maximum;
-
- if (minimum === undefined || maximum === undefined) {
- return nullFunction;
- }
-
- const delta = maximum - minimum;
- if (delta === 0.0) {
- return nullFunction;
- }
-
- const values = valuesAsNumbers.values;
- return function (rowIndex: number) {
- const value = values[rowIndex];
- if (value === null) {
- return null;
- }
- return (value - minimum) / delta;
- };
- }
-
- return nullFunction;
- }
-
private guessColumnTypeFromValues(): TableColumnType {
let type: TableColumnType | undefined;
@@ -919,7 +890,3 @@ function toNumber(value: string): number | null {
}
return null;
}
-
-function nullFunction(rowIndex: number) {
- return null;
-}
diff --git a/lib/Table/TableFeatureInfoStratum.ts b/lib/Table/TableFeatureInfoStratum.ts
index e5d178f4434..49a39855c32 100644
--- a/lib/Table/TableFeatureInfoStratum.ts
+++ b/lib/Table/TableFeatureInfoStratum.ts
@@ -1,11 +1,12 @@
+import { computed, makeObservable } from "mobx";
+import { FEATURE_ID_PROP } from "../ModelMixins/GeojsonMixin";
import TableMixin from "../ModelMixins/TableMixin";
import LoadableStratum from "../Models/Definition/LoadableStratum";
import { BaseModel } from "../Models/Definition/Model";
-import TableTraits from "../Traits/TraitsClasses/Table/TableTraits";
-import { computed, makeObservable } from "mobx";
+import StratumOrder from "../Models/Definition/StratumOrder";
import createStratumInstance from "../Models/Definition/createStratumInstance";
import { FeatureInfoTemplateTraits } from "../Traits/TraitsClasses/FeatureInfoTraits";
-import StratumOrder from "../Models/Definition/StratumOrder";
+import TableTraits from "../Traits/TraitsClasses/Table/TableTraits";
export default class TableFeatureInfoStratum extends LoadableStratum(
TableTraits
@@ -29,6 +30,7 @@ export default class TableFeatureInfoStratum extends LoadableStratum(
let template = '';
template += this.catalogItem.tableColumns
+ ?.filter((col) => col.name !== FEATURE_ID_PROP)
?.map(
(col) =>
`${col.title} {{${col.name}}} `
diff --git a/lib/ThirdParty/proj4-fully-loaded/index.d.ts b/lib/ThirdParty/proj4-fully-loaded/index.d.ts
new file mode 100644
index 00000000000..9cfa1dd2df9
--- /dev/null
+++ b/lib/ThirdParty/proj4-fully-loaded/index.d.ts
@@ -0,0 +1 @@
+declare module "proj4-fully-loaded";
diff --git a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts
index 0fabbcee06a..3b3c21e18ed 100644
--- a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts
+++ b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts
@@ -2,6 +2,7 @@ declare module "terriajs-cesium/Source/Scene/TweenCollection" {
export default class TweenCollection {
get length(): number;
add(options: any): any;
+ update(time?: number): void;
}
}
@@ -44,25 +45,24 @@ declare module "terriajs-cesium/Source/Core/PolygonGeometryLibrary";
declare module "terriajs-cesium/Source/DataSources/getElement";
-declare interface Axis {
- X: number;
- Y: number;
- Z: number;
- fromName(name: string): number;
-}
-
-declare interface FeatureDetection {
- isEdge(): boolean;
- isInternetExplorer(): boolean;
- internetExplorerVersion(): number[];
- chromeVersion(): number[];
-}
-
// This is a workaround for Cesium's incorrect type declaration for raiseEvent.
declare module "terriajs-cesium" {
export interface Event {
raiseEvent(...arguments: any[]): void;
}
+
+ namespace FeatureDetection {
+ function isChrome(): boolean;
+ function isEdge(): boolean;
+ function isInternetExplorer(): boolean;
+ function isFirefox(): boolean;
+ function internetExplorerVersion(): number[];
+ function chromeVersion(): number[];
+ }
+
+ namespace Axis {
+ function fromName(name: string): number;
+ }
}
// Begin Generated Declarations
diff --git a/lib/ThirdParty/xml2json.d.ts b/lib/ThirdParty/xml2json.d.ts
new file mode 100644
index 00000000000..7e663dfa272
--- /dev/null
+++ b/lib/ThirdParty/xml2json.d.ts
@@ -0,0 +1,4 @@
+export default function xml2json(
+ xml: XMLDocument | string | undefined,
+ extended?: boolean
+): any;
diff --git a/lib/ThirdParty/xml2json.js b/lib/ThirdParty/xml2json.js
index fcd396f09c4..61ae6d160cd 100644
--- a/lib/ThirdParty/xml2json.js
+++ b/lib/ThirdParty/xml2json.js
@@ -180,4 +180,4 @@ function text2xml(str) {
return parser.parseFromString(str, "text/xml");
}
-module.exports = xml2json;
+export default xml2json;
diff --git a/lib/Traits/Decorators/modelReferenceArrayTrait.ts b/lib/Traits/Decorators/modelReferenceArrayTrait.ts
index e46244e224a..c6aa430b976 100644
--- a/lib/Traits/Decorators/modelReferenceArrayTrait.ts
+++ b/lib/Traits/Decorators/modelReferenceArrayTrait.ts
@@ -13,7 +13,7 @@ export interface ModelArrayTraitOptions extends TraitOptions {
factory?: ModelFactory;
}
-export default function modelReferenceArrayTrait(
+export default function modelReferenceArrayTrait<_T>(
options: ModelArrayTraitOptions
) {
return function (target: any, propertyKey: string) {
diff --git a/lib/Traits/Decorators/modelReferenceTrait.ts b/lib/Traits/Decorators/modelReferenceTrait.ts
index 122ac276831..1cf346af379 100644
--- a/lib/Traits/Decorators/modelReferenceTrait.ts
+++ b/lib/Traits/Decorators/modelReferenceTrait.ts
@@ -12,7 +12,7 @@ export interface ModelTraitOptions extends TraitOptions {
factory?: ModelFactory;
}
-export default function modelReferenceTrait(options: ModelTraitOptions) {
+export default function modelReferenceTrait<_T>(options: ModelTraitOptions) {
return function (target: any, propertyKey: string) {
const constructor = target.constructor;
if (!constructor.traits) {
diff --git a/lib/Traits/Decorators/primitiveArrayTrait.ts b/lib/Traits/Decorators/primitiveArrayTrait.ts
index e91a6cbebc8..68aa7f893f0 100644
--- a/lib/Traits/Decorators/primitiveArrayTrait.ts
+++ b/lib/Traits/Decorators/primitiveArrayTrait.ts
@@ -5,7 +5,7 @@ import Trait, { TraitOptions } from "../Trait";
type PrimitiveType = "string" | "number" | "boolean";
-export interface PrimitiveArrayTraitOptions extends TraitOptions {
+export interface PrimitiveArrayTraitOptions<_T> extends TraitOptions {
type: PrimitiveType;
isNullable?: boolean;
}
diff --git a/lib/Traits/Decorators/primitiveTrait.ts b/lib/Traits/Decorators/primitiveTrait.ts
index 19f49e47a5b..658261a2839 100644
--- a/lib/Traits/Decorators/primitiveTrait.ts
+++ b/lib/Traits/Decorators/primitiveTrait.ts
@@ -5,7 +5,7 @@ import Trait, { TraitOptions } from "../Trait";
type PrimitiveType = "string" | "number" | "boolean";
-export interface PrimitiveTraitOptions extends TraitOptions {
+export interface PrimitiveTraitOptions<_T> extends TraitOptions {
type: PrimitiveType;
isNullable?: boolean;
}
diff --git a/lib/Traits/TraitsClasses/ArcGisImageServerCatalogItemTraits.ts b/lib/Traits/TraitsClasses/ArcGisImageServerCatalogItemTraits.ts
new file mode 100644
index 00000000000..9826ac0a2c1
--- /dev/null
+++ b/lib/Traits/TraitsClasses/ArcGisImageServerCatalogItemTraits.ts
@@ -0,0 +1,175 @@
+import { JsonObject } from "../../Core/Json";
+import anyTrait from "../Decorators/anyTrait";
+import objectArrayTrait from "../Decorators/objectArrayTrait";
+import objectTrait from "../Decorators/objectTrait";
+import primitiveArrayTrait from "../Decorators/primitiveArrayTrait";
+import primitiveTrait from "../Decorators/primitiveTrait";
+import ModelTraits from "../ModelTraits";
+import { traitClass } from "../Trait";
+import mixTraits from "../mixTraits";
+import CatalogMemberTraits from "./CatalogMemberTraits";
+import DiscretelyTimeVaryingTraits from "./DiscretelyTimeVaryingTraits";
+import ImageryProviderTraits from "./ImageryProviderTraits";
+import LayerOrderingTraits from "./LayerOrderingTraits";
+import LegendOwnerTraits from "./LegendOwnerTraits";
+import { MinMaxLevelTraits } from "./MinMaxLevelTraits";
+import UrlTraits from "./UrlTraits";
+
+export class ArcGisImageServerRenderingRule extends ModelTraits {
+ @primitiveTrait({
+ type: "string",
+ name: "Name",
+ description: "The name of the raster function."
+ })
+ rasterFunction?: string;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Description",
+ description:
+ 'optional for well known functions, default is "Raster" for raster function templates.'
+ })
+ variableName?: string;
+
+ @anyTrait({
+ name: "Arguments",
+ description:
+ "Overwrite the raster function default configuration by specifying argument parameters (argument names and value types are defined by the author of each raster function template and are not discoverable through ArcGis REST API)."
+ })
+ rasterFunctionArguments?: JsonObject;
+}
+
+export class ArcGisImageServerAvailableRasterFunctionTraits extends ModelTraits {
+ @primitiveTrait({
+ type: "string",
+ name: "Name",
+ description: "The name of the raster function."
+ })
+ name?: string;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Description",
+ description: "The description of the raster function."
+ })
+ description?: string;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Unit",
+ description: "Help text for the raster function"
+ })
+ help?: string;
+}
+
+@traitClass({
+ example: {
+ url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/CharlotteLAS/ImageServer",
+ type: "esri-imageServer",
+ name: "CharlotteLAS"
+ }
+})
+export default class ArcGisImageServerCatalogItemTraits extends mixTraits(
+ ImageryProviderTraits,
+ LayerOrderingTraits,
+ UrlTraits,
+ CatalogMemberTraits,
+ LegendOwnerTraits,
+ DiscretelyTimeVaryingTraits,
+ MinMaxLevelTraits
+) {
+ @primitiveTrait({
+ type: "number",
+ name: "Maximum scale",
+ description:
+ "Gets or sets the denominator of the largest scale (smallest denominator) for which tiles should be requested. For example, if this value is 1000, then tiles representing a scale larger than 1:1000 (i.e. numerically smaller denominator, when zooming in closer) will not be requested. Instead, tiles of the largest-available scale, as specified by this property, will be used and will simply get blurier as the user zooms in closer. Note: maximumLevel overrides this property."
+ })
+ maximumScale?: number;
+
+ @anyTrait({
+ name: "Parameters",
+ description:
+ "Additional parameters to pass to the ImageServer when requesting images."
+ })
+ parameters?: JsonObject;
+
+ @primitiveTrait({
+ name: "Token URL",
+ description: "URL to use for fetching request tokens",
+ type: "string"
+ })
+ tokenUrl?: string;
+
+ @primitiveTrait({
+ name: "Token",
+ description:
+ "Token to use for fetching request tokens (if not using tokenUrl)",
+ type: "string"
+ })
+ token?: string;
+
+ @primitiveTrait({
+ type: "number",
+ name: "Maximum Refresh Intervals",
+ description:
+ "The maximum number of discrete times that can be created by a single " +
+ "date range when layer in time-enabled."
+ })
+ maxRefreshIntervals: number = 10000;
+
+ @primitiveTrait({
+ type: "number",
+ name: "WKID",
+ description:
+ "The well-known ID of the spatial reference of the image server. Only Web Mercator (102100 or 102113 or 3857) and WGS84 (4326) are supported."
+ })
+ wkid?: number = 102100;
+
+ @primitiveTrait({
+ name: "Use Pre-Cached Tiles",
+ description:
+ "If true, the server's pre-cached tiles are used. If false, then the ImageServer exportImage endpoint will be used. This will default to false if parameters (including time) have been specified, otherwise it will default to true if a server supports pre-cached tiles.",
+ type: "boolean"
+ })
+ usePreCachedTiles?: boolean;
+
+ @primitiveArrayTrait({
+ name: "Band IDs",
+ description: "The band IDs to use when requesting images.",
+ type: "number"
+ })
+ bandIds?: number[];
+
+ @objectTrait({
+ name: "Rendering Rule",
+ description:
+ 'The rendering rule to apply to the image service. This must be a JSON object - for example `{"rasterFunction": "RFTAspectColor"}`. Note `allowRasterFunction` must be true for this to be applied.',
+ type: ArcGisImageServerRenderingRule
+ })
+ renderingRule?: ArcGisImageServerRenderingRule;
+
+ @primitiveTrait({
+ name: "Allow Raster Function",
+ description:
+ "If true, then the renderingRule will be applied to the image service. If false, the renderingRule will be ignored. This will default to true if an image service supports raster functions.",
+ type: "boolean"
+ })
+ allowRasterFunction?: boolean;
+
+ @objectArrayTrait({
+ type: ArcGisImageServerAvailableRasterFunctionTraits,
+ name: "Available raster functions",
+ description:
+ "The available raster functions for the ImageServer. Defaults to all raster functions in the service if the server supports raster functions. Note: `allowRasterFunction` must be true. To set the default raster function, use the `renderingRule` property.",
+ idProperty: "name"
+ })
+ availableRasterFunctions?: ArcGisImageServerAvailableRasterFunctionTraits[];
+
+ @primitiveTrait({
+ name: "Disable raster functions selectors",
+ description:
+ "When true, disables the dimension selectors in the workbench. This will default to true if the server does not support raster functions.",
+ type: "boolean"
+ })
+ disableRasterFunctionSelectors?: boolean;
+}
diff --git a/lib/Traits/TraitsClasses/ArcGisMapServerCatalogItemTraits.ts b/lib/Traits/TraitsClasses/ArcGisMapServerCatalogItemTraits.ts
index 269ba456624..0778cbc4525 100644
--- a/lib/Traits/TraitsClasses/ArcGisMapServerCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/ArcGisMapServerCatalogItemTraits.ts
@@ -67,7 +67,7 @@ export default class ArcGisMapServerCatalogItemTraits extends mixTraits(
"The maximum number of discrete times that can be created by a single " +
"date range when layer in time-enabled."
})
- maxRefreshIntervals: number = 1000;
+ maxRefreshIntervals: number = 10000;
@primitiveTrait({
name: "Time Window Duration",
@@ -94,7 +94,7 @@ export default class ArcGisMapServerCatalogItemTraits extends mixTraits(
isForwardTimeWindow: boolean = true;
@primitiveTrait({
- name: "Is Forward Time Window",
+ name: "Use Pre-Cached Tiles If Available",
description:
"If true, the server's pre-cached tiles are used if they are available. If false, then the MapServer export endpoint will be used. This will default to true if no specific layers are fetched (i.e. all layers are fetched). Otherwise, it will default to false. This will also default to false if parameters have been specified",
type: "boolean"
diff --git a/lib/Traits/TraitsClasses/CatalogMemberTraits.ts b/lib/Traits/TraitsClasses/CatalogMemberTraits.ts
index 9ddf821411d..60515d25038 100644
--- a/lib/Traits/TraitsClasses/CatalogMemberTraits.ts
+++ b/lib/Traits/TraitsClasses/CatalogMemberTraits.ts
@@ -100,6 +100,7 @@ export class ShortReportTraits extends ModelTraits {
show = true;
}
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
class CatalogMemberTraits extends ModelTraits {
@primitiveTrait({
type: "string",
@@ -238,8 +239,17 @@ class CatalogMemberTraits extends ModelTraits {
description: "Disables the 'About Data' button in the workbench."
})
disableAboutData?: boolean;
+
+ @primitiveTrait({
+ type: "boolean",
+ name: "Shareable",
+ description:
+ "True (default) if this catalog member may be included in share links. False to exclude it from share links."
+ })
+ shareable: boolean = true;
}
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
interface CatalogMemberTraits {
// Add traits here that you want to override from some Mixin or Model class
// without generating TS2611 type error.
diff --git a/lib/Traits/TraitsClasses/Cesium3DTilesCatalogItemTraits.ts b/lib/Traits/TraitsClasses/Cesium3DTilesCatalogItemTraits.ts
index 6abd74fb01f..69b2143e288 100644
--- a/lib/Traits/TraitsClasses/Cesium3DTilesCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/Cesium3DTilesCatalogItemTraits.ts
@@ -12,7 +12,6 @@ import UrlTraits from "./UrlTraits";
@traitClass({
description: `Creates a 3d tiles item in the catalog from an ION Asset ID.
-
Note: Instead of specifying ionAssetId property, you can also provide a URL, for example, "url": "https://storage.googleapis.com/vic-datasets-public/1ce41fe7-aed2-4ad3-be4d-c38b715ce9af/v1/tileset.json"
. `,
example: {
type: "3d-tiles",
diff --git a/lib/Traits/TraitsClasses/Cesium3dTilesTraits.ts b/lib/Traits/TraitsClasses/Cesium3dTilesTraits.ts
index b3e88b8b9cb..c83849c49a5 100644
--- a/lib/Traits/TraitsClasses/Cesium3dTilesTraits.ts
+++ b/lib/Traits/TraitsClasses/Cesium3dTilesTraits.ts
@@ -18,6 +18,7 @@ import SplitterTraits from "./SplitterTraits";
import TransformationTraits from "./TransformationTraits";
import UrlTraits from "./UrlTraits";
import FeaturePickingTraits from "./FeaturePickingTraits";
+import CesiumIonTraits from "./CesiumIonTraits";
export class FilterTraits extends ModelTraits {
@primitiveTrait({
@@ -123,29 +124,9 @@ export default class Cesium3DTilesTraits extends mixTraits(
LegendOwnerTraits,
ShadowTraits,
ClippingPlanesTraits,
- SplitterTraits
+ SplitterTraits,
+ CesiumIonTraits
) {
- @primitiveTrait({
- type: "number",
- name: "Ion asset ID",
- description: "The Cesium Ion asset id."
- })
- ionAssetId?: number;
-
- @primitiveTrait({
- type: "string",
- name: "Ion access token",
- description: "Cesium Ion access token id."
- })
- ionAccessToken?: string;
-
- @primitiveTrait({
- type: "string",
- name: "Ion server",
- description: "URL of the Cesium Ion API server."
- })
- ionServer?: string;
-
@objectTrait({
type: OptionsTraits,
name: "options",
diff --git a/lib/Traits/TraitsClasses/CesiumIonTraits.ts b/lib/Traits/TraitsClasses/CesiumIonTraits.ts
new file mode 100644
index 00000000000..72a1ff7a2cc
--- /dev/null
+++ b/lib/Traits/TraitsClasses/CesiumIonTraits.ts
@@ -0,0 +1,28 @@
+import primitiveTrait from "../Decorators/primitiveTrait";
+import ModelTraits from "../ModelTraits";
+
+export default class CesiumIonTraits extends ModelTraits {
+ @primitiveTrait({
+ type: "number",
+ name: "Cesium ion asset ID",
+ description:
+ "The Cesium ion asset id. If this is set then the `url` is ignored"
+ })
+ ionAssetId?: number;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Cesium ion access token",
+ description:
+ "Cesium ion access token. If not specified, the default token is used."
+ })
+ ionAccessToken?: string;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Ion server",
+ description:
+ "URL of the Cesium ion API server. If not specified, the default Ion server, `https://api.cesium.com/`, is used."
+ })
+ ionServer?: string;
+}
diff --git a/lib/Traits/TraitsClasses/CesiumTerrainCatalogItemTraits.ts b/lib/Traits/TraitsClasses/CesiumTerrainCatalogItemTraits.ts
index 7558d3cfed8..60a4de6bef1 100644
--- a/lib/Traits/TraitsClasses/CesiumTerrainCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/CesiumTerrainCatalogItemTraits.ts
@@ -1,9 +1,9 @@
import CatalogMemberTraits from "./CatalogMemberTraits";
import MappableTraits from "./MappableTraits";
import mixTraits from "../mixTraits";
-import primitiveTrait from "../Decorators/primitiveTrait";
import UrlTraits from "./UrlTraits";
import { traitClass } from "../Trait";
+import CesiumIonTraits from "./CesiumIonTraits";
@traitClass({
description: `Creates a Cesium terrain item in the catalog from url.`,
@@ -19,28 +19,6 @@ import { traitClass } from "../Trait";
export default class CesiumTerrainCatalogItemTraits extends mixTraits(
UrlTraits,
MappableTraits,
- CatalogMemberTraits
-) {
- @primitiveTrait({
- name: "Ion Asset ID",
- type: "number",
- description: "The ID of the Cesium Ion Asset. If this is set url is ignored"
- })
- ionAssetId?: number;
-
- @primitiveTrait({
- name: "Ion Access Token",
- type: "string",
- description:
- "The Cesium Ion access token to use to access the terrain. If not specified, the token"
- })
- ionAccessToken?: string;
-
- @primitiveTrait({
- name: "Ion Server",
- type: "string",
- description:
- "the Cesium Ion access token to use to access the terrain. If not specified, the default Ion server, `https://api.cesium.com/`"
- })
- ionServer?: string;
-}
+ CatalogMemberTraits,
+ CesiumIonTraits
+) {}
diff --git a/lib/Traits/TraitsClasses/CogCatalogItemTraits.ts b/lib/Traits/TraitsClasses/CogCatalogItemTraits.ts
new file mode 100644
index 00000000000..d6929891005
--- /dev/null
+++ b/lib/Traits/TraitsClasses/CogCatalogItemTraits.ts
@@ -0,0 +1,89 @@
+import objectTrait from "../Decorators/objectTrait";
+import primitiveTrait from "../Decorators/primitiveTrait";
+import ModelTraits from "../ModelTraits";
+import { traitClass } from "../Trait";
+import mixTraits from "../mixTraits";
+import CatalogMemberTraits from "./CatalogMemberTraits";
+import ImageryProviderTraits from "./ImageryProviderTraits";
+import LayerOrderingTraits from "./LayerOrderingTraits";
+import LegendOwnerTraits from "./LegendOwnerTraits";
+import MappableTraits from "./MappableTraits";
+import UrlTraits from "./UrlTraits";
+
+export class CogRenderOptionsTraits extends ModelTraits {
+ @primitiveTrait({
+ type: "number",
+ name: "No Data Value",
+ description: "No data value, default read from tiff meta"
+ })
+ nodata?: number;
+
+ @primitiveTrait({
+ type: "boolean",
+ name: "Convert to RGB",
+ description: "Try to render multi band cog to RGB, priority 1"
+ })
+ convertToRGB?: boolean;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Resample Method",
+ description: "Geotiff resample method. Defaults to `bilinear`."
+ })
+ resampleMethod?: "nearest" | "bilinear" = "nearest";
+}
+
+@traitClass({
+ description:
+ "Creates a Cloud Optimised Geotiff item in the catalog from a url pointing to a TIFF that is a valid COG.",
+ example: {
+ name: "COG Test Uluru",
+ description:
+ "This is a COG from Sentinel-2 L2A, in EPSG:32752. Does it display in correct location? Does it display correctly?",
+ type: "cog",
+ url: "https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/52/J/FS/2023/5/S2A_52JFS_20230501_0_L2A/TCI.tif"
+ }
+})
+export default class CogCatalogItemTraits extends mixTraits(
+ ImageryProviderTraits,
+ LayerOrderingTraits,
+ UrlTraits,
+ MappableTraits,
+ CatalogMemberTraits,
+ LegendOwnerTraits
+) {
+ @objectTrait({
+ type: CogRenderOptionsTraits,
+ name: "Render Options",
+ description: "Render options for COGs"
+ })
+ renderOptions?: CogRenderOptionsTraits;
+
+ @primitiveTrait({
+ type: "string",
+ name: "Credit",
+ description: "Credit for the imagery provider."
+ })
+ credit?: string;
+
+ @primitiveTrait({
+ type: "number",
+ name: "Tile Size",
+ description: "The size of the tile."
+ })
+ tileSize?: number;
+
+ @primitiveTrait({
+ type: "boolean",
+ name: "Has Alpha Channel",
+ description: "Whether the imagery has an alpha channel."
+ })
+ hasAlphaChannel?: boolean;
+
+ @primitiveTrait({
+ type: "number",
+ name: "Cache",
+ description: "Cache survival time in milliseconds."
+ })
+ cache?: number;
+}
diff --git a/lib/Traits/TraitsClasses/CzmlCatalogItemTraits.ts b/lib/Traits/TraitsClasses/CzmlCatalogItemTraits.ts
index cfd267a0f6f..51fb9b0cd1c 100644
--- a/lib/Traits/TraitsClasses/CzmlCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/CzmlCatalogItemTraits.ts
@@ -5,6 +5,7 @@ import { traitClass } from "../Trait";
import mixTraits from "../mixTraits";
import AutoRefreshingTraits from "./AutoRefreshingTraits";
import CatalogMemberTraits from "./CatalogMemberTraits";
+import CesiumIonTraits from "./CesiumIonTraits";
import LegendOwnerTraits from "./LegendOwnerTraits";
import MappableTraits from "./MappableTraits";
import TimeVaryingTraits from "./TimeVaryingTraits";
@@ -12,7 +13,7 @@ import UrlTraits from "./UrlTraits";
@traitClass({
description: `Creates one catalog item from url that points to a czml file.
-
+
Note: If the model is not visible, try to disable the terrain by unchecking the box "Terrain hides underground features".`,
example: {
type: "czml",
@@ -27,7 +28,8 @@ export default class CzmlCatalogItemTraits extends mixTraits(
UrlTraits,
CatalogMemberTraits,
LegendOwnerTraits,
- MappableTraits
+ MappableTraits,
+ CesiumIonTraits
) {
@anyTrait({
name: "CZML Data",
diff --git a/lib/Traits/TraitsClasses/DiffableTraits.ts b/lib/Traits/TraitsClasses/DiffableTraits.ts
index 28d20559a91..07a32251890 100644
--- a/lib/Traits/TraitsClasses/DiffableTraits.ts
+++ b/lib/Traits/TraitsClasses/DiffableTraits.ts
@@ -1,3 +1,5 @@
+import { JsonObject } from "../../Core/Json";
+import anyTrait from "../Decorators/anyTrait";
import primitiveArrayTrait from "../Decorators/primitiveArrayTrait";
import primitiveTrait from "../Decorators/primitiveTrait";
import mixTraits from "../mixTraits";
@@ -39,4 +41,10 @@ export default class DiffableTraits extends mixTraits(TimeFilterTraits) {
description: "The ID of the style used to compute the difference image"
})
diffStyleId?: string;
+
+ @anyTrait({
+ name: "Difference item properties",
+ description: "Additional properties to set on the difference output item."
+ })
+ diffItemProperties?: JsonObject;
}
diff --git a/lib/Traits/TraitsClasses/GeoJsonCatalogItemTraits.ts b/lib/Traits/TraitsClasses/GeoJsonCatalogItemTraits.ts
index 2d8ec988934..fcfbe57b1ba 100644
--- a/lib/Traits/TraitsClasses/GeoJsonCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/GeoJsonCatalogItemTraits.ts
@@ -5,6 +5,7 @@ import primitiveTrait from "../Decorators/primitiveTrait";
import { traitClass } from "../Trait";
import mixTraits from "../mixTraits";
import ApiRequestTraits from "./ApiRequestTraits";
+import CesiumIonTraits from "./CesiumIonTraits";
import { GeoJsonTraits } from "./GeoJsonTraits";
@traitClass({
@@ -18,7 +19,8 @@ import { GeoJsonTraits } from "./GeoJsonTraits";
})
export default class GeoJsonCatalogItemTraits extends mixTraits(
GeoJsonTraits,
- ApiRequestTraits
+ ApiRequestTraits,
+ CesiumIonTraits
) {
@objectArrayTrait({
type: ApiRequestTraits,
diff --git a/lib/Traits/TraitsClasses/GltfCatalogItemTraits.ts b/lib/Traits/TraitsClasses/GltfCatalogItemTraits.ts
index a20aec67960..d0371b4017f 100644
--- a/lib/Traits/TraitsClasses/GltfCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/GltfCatalogItemTraits.ts
@@ -1,6 +1,7 @@
import { traitClass } from "../Trait";
import mixTraits from "../mixTraits";
import AutoRefreshingTraits from "./AutoRefreshingTraits";
+import CesiumIonTraits from "./CesiumIonTraits";
import GltfTraits from "./GltfTraits";
import PlaceEditorTraits from "./PlaceEditorTraits";
import UrlTraits from "./UrlTraits";
@@ -24,5 +25,6 @@ export default class GltfCatalogItemTraits extends mixTraits(
UrlTraits,
AutoRefreshingTraits,
PlaceEditorTraits,
- GltfTraits
+ GltfTraits,
+ CesiumIonTraits
) {}
diff --git a/lib/Traits/TraitsClasses/I3SCatalogItemTraits.ts b/lib/Traits/TraitsClasses/I3SCatalogItemTraits.ts
new file mode 100644
index 00000000000..7604da9845d
--- /dev/null
+++ b/lib/Traits/TraitsClasses/I3SCatalogItemTraits.ts
@@ -0,0 +1,17 @@
+import { traitClass } from "../Trait";
+import mixTraits from "../mixTraits";
+import I3STraits from "./I3STraits";
+import Cesium3DTilesCatalogItemTraits from "./Cesium3DTilesCatalogItemTraits";
+
+@traitClass({
+ description: `Creates an I3S item in the catalog from an slpk.`,
+ example: {
+ type: "I3S",
+ name: "CoM Melbourne 3D Photo Mesh",
+ id: "some-unique-id"
+ }
+})
+export default class I3SCatalogItemTraits extends mixTraits(
+ Cesium3DTilesCatalogItemTraits,
+ I3STraits
+) {}
diff --git a/lib/Traits/TraitsClasses/I3STraits.ts b/lib/Traits/TraitsClasses/I3STraits.ts
new file mode 100644
index 00000000000..715efaa8cfb
--- /dev/null
+++ b/lib/Traits/TraitsClasses/I3STraits.ts
@@ -0,0 +1,20 @@
+import primitiveArrayTrait from "../Decorators/primitiveArrayTrait";
+import primitiveTrait from "../Decorators/primitiveTrait";
+import ModelTraits from "../ModelTraits";
+
+export default class I3STraits extends ModelTraits {
+ @primitiveTrait({
+ type: "string",
+ name: "Terrain URL",
+ description:
+ "URL to construct ArcGISTiledElevationTerrainProvider for I3S geometry."
+ })
+ terrainURL?: string;
+
+ @primitiveArrayTrait({
+ type: "number",
+ name: "Image based lighting factor",
+ description: "Cartesian2 of lighting factor for imageBasedLightingFactor"
+ })
+ lightingFactor?: [number, number];
+}
diff --git a/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts b/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts
index 76713ee85c2..482e5ee974c 100644
--- a/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts
@@ -1,6 +1,7 @@
import primitiveTrait from "../Decorators/primitiveTrait";
import mixTraits from "../mixTraits";
import CatalogMemberTraits from "./CatalogMemberTraits";
+import CesiumIonTraits from "./CesiumIonTraits";
import LegendOwnerTraits from "./LegendOwnerTraits";
import MappableTraits from "./MappableTraits";
import UrlTraits from "./UrlTraits";
@@ -9,7 +10,8 @@ export default class KmlCatalogItemTraits extends mixTraits(
UrlTraits,
MappableTraits,
CatalogMemberTraits,
- LegendOwnerTraits
+ LegendOwnerTraits,
+ CesiumIonTraits
) {
@primitiveTrait({
type: "string",
diff --git a/lib/Traits/TraitsClasses/MappableTraits.ts b/lib/Traits/TraitsClasses/MappableTraits.ts
index f50d45e7207..a46678a3290 100644
--- a/lib/Traits/TraitsClasses/MappableTraits.ts
+++ b/lib/Traits/TraitsClasses/MappableTraits.ts
@@ -199,6 +199,7 @@ export class InitialMessageTraits extends ModelTraits {
height?: number;
}
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
class MappableTraits extends mixTraits(AttributionTraits) {
@objectTrait({
type: RectangleTraits,
@@ -280,6 +281,7 @@ class MappableTraits extends mixTraits(AttributionTraits) {
maximumShownFeatureInfos?: number;
}
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
interface MappableTraits {
// Add traits here that you want to override from some Mixin or Model class
// without generating TS2611 type error.
diff --git a/lib/Traits/TraitsClasses/UrlTraits.ts b/lib/Traits/TraitsClasses/UrlTraits.ts
index f878e92a742..52520d2b8e1 100644
--- a/lib/Traits/TraitsClasses/UrlTraits.ts
+++ b/lib/Traits/TraitsClasses/UrlTraits.ts
@@ -1,6 +1,7 @@
import ModelTraits from "../ModelTraits";
import primitiveTrait from "../Decorators/primitiveTrait";
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
class UrlTraits extends ModelTraits {
@primitiveTrait({
type: "string",
@@ -25,6 +26,7 @@ class UrlTraits extends ModelTraits {
cacheDuration?: string;
}
+/* eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging */
interface UrlTraits {
// Add traits here that you want to override from some Mixin or Model class
// without generating TS2611 type error.
diff --git a/lib/Traits/TraitsClasses/WebMapServiceCatalogItemTraits.ts b/lib/Traits/TraitsClasses/WebMapServiceCatalogItemTraits.ts
index deb3ddffc32..459858448ae 100644
--- a/lib/Traits/TraitsClasses/WebMapServiceCatalogItemTraits.ts
+++ b/lib/Traits/TraitsClasses/WebMapServiceCatalogItemTraits.ts
@@ -239,7 +239,7 @@ export default class WebMapServiceCatalogItemTraits extends mixTraits(
"date range, when specified in the format time/time/periodicity. E.g. " +
"`2015-04-27T16:15:00/2015-04-27T18:45:00/PT15M` has 11 times."
})
- maxRefreshIntervals: number = 1000;
+ maxRefreshIntervals: number = 10000;
@primitiveTrait({
type: "boolean",
diff --git a/package.json b/package.json
index 8602e5459a8..fd43252e2a1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "terriajs",
- "version": "8.7.3",
+ "version": "8.7.7",
"description": "Geospatial data visualization platform.",
"license": "Apache-2.0",
"engines": {
@@ -42,12 +42,11 @@
"@turf/meta": "^6.5.0",
"@types/arcgis-rest-api": "^10.4.5",
"@types/create-react-class": "^15.6.2",
- "@types/d3-array": "^2.0.0",
- "@types/d3-axis": "^1.0.12",
+ "@types/d3-array": "^3.2.1",
"@types/d3-color": "^3.0.0",
- "@types/d3-scale-chromatic": "^2.0.0",
- "@types/d3-selection": "^1.4.1",
- "@types/d3-transition": "^1.1.4",
+ "@types/d3-scale-chromatic": "^3.0.3",
+ "@types/d3-selection": "^3.0.10",
+ "@types/d3-transition": "^3.0.8",
"@types/dateformat": "^3.0.1",
"@types/dompurify": "^2.3.1",
"@types/file-saver": "^1.3.0",
@@ -55,17 +54,18 @@
"@types/fs-extra": "^7.0.0",
"@types/jasmine": "^2.8.8",
"@types/jasmine-ajax": "^3.3.0",
- "@types/json5": "^0.0.30",
- "@types/leaflet": "^1.7.10",
+ "@types/leaflet": "^1.9.12",
+ "@types/linkify-it": "^3.0.5",
"@types/lodash-es": "^4.17.3",
+ "@types/markdown-it": "^14.0.1",
"@types/math-expression-evaluator": "^1.2.0",
"@types/ms": "^0.7.31",
"@types/mustache": "^0.8.32",
"@types/node-fetch": "^2.6.2",
"@types/papaparse": "^4.5.9",
"@types/pbf": "^3.0.1",
+ "@types/proj4": "^2.5.5",
"@types/rbush": "^3.0.0",
- "@types/rc-slider": "^8.6.6",
"@types/react": "^17.0.3",
"@types/react-color": "^3.0.6",
"@types/react-dom": "^17.0.2",
@@ -97,21 +97,18 @@
"commander": "^11.1.0 ",
"copy-webpack-plugin": "^6.4.0",
"core-js": "^3.1.4",
+ "create-react-class": "^15.7.0",
"css-loader": "^2.1.0",
"css-modules-typescript-loader": "^2.0.4",
- "d3-array": "^1.0.0",
- "d3-axis": "^1.0.0",
- "d3-collection": "^1.0.0",
- "d3-color": "^3.0.1",
- "d3-dispatch": "^1.0.5",
- "d3-ease": "^1.0.5",
- "d3-interpolate": "^1.3.2",
- "d3-scale": "^2.2.2",
- "d3-scale-chromatic": "^2.0.0",
- "d3-selection": "^1.0.0",
- "d3-shape": "^1.0.0",
- "d3-transition": "^1.0.0",
- "d3-zoom": "^1.8.3",
+ "d3-array": "^3.2.4",
+ "d3-color": "^3.1.0",
+ "d3-ease": "^3.0.1",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale-chromatic": "^3.1.0",
+ "d3-selection": "^3.0.0",
+ "d3-shape": "^3.2.0",
+ "d3-transition": "^3.0.1",
+ "d3-zoom": "^3.0.0",
"dateformat": "^3.0.3",
"dompurify": "^2.3.3",
"fetch-mock": "^9.11.0",
@@ -133,9 +130,9 @@
"javascript-natural-sort": "^0.7.1",
"json5": "^2.1.0",
"leaflet": "^1.8.0",
- "linkify-it": "^2.0.0",
+ "linkify-it": "^5.0.0",
"lodash-es": "^4.17.11",
- "markdown-it": "^11.0.0",
+ "markdown-it": "^14.1.0",
"math-expression-evaluator": "^1.3.7",
"mini-css-extract-plugin": "^0.5.0",
"minisearch": "^3.0.2",
@@ -150,6 +147,7 @@
"pbf": "^3.0.1",
"point-in-polygon": "^1.0.1",
"proj4": "^2.4.4",
+ "proj4-fully-loaded": "^0.2.0",
"prop-types": "^15.6.0",
"protomaps": "1.19.0",
"raw-loader": "^1.0.0",
@@ -169,7 +167,6 @@
"react-virtual": "~2.3.2",
"resolve-url-loader": "^5.0.0",
"retry": "^0.12.0",
- "rollbar": "^2.24.0",
"sass-loader": "^10",
"shpjs": "^4.0.4",
"simple-statistics": "^7.0.1",
@@ -177,9 +174,10 @@
"style-loader": "^0.23.1",
"styled-components": "^5.3.9",
"svg-sprite-loader": "^6.0.11",
- "terriajs-cesium": "8.0.0",
+ "terriajs-cesium": "8.0.1",
"terriajs-cesium-widgets": "5.0.0",
"terriajs-html2canvas": "1.0.0-alpha.12-terriajs-1",
+ "terriajs-tiff-imagery-provider": "2.13.3",
"thredds-catalog-crawler": "0.0.7",
"ts-essentials": "^5.0.0",
"ts-loader": "^5.3.3",
@@ -235,7 +233,7 @@
"react-shallow-testutils": "^3.0.0",
"react-test-renderer": "^16.3.2",
"regenerator-runtime": "^0.13.2",
- "sass": "^1.66.1",
+ "sass": "^1.79.1",
"terriajs-server": "^4.0.0",
"utf-8-validate": "^6.0.3",
"yaml": "^1.10.0"
diff --git a/test/Core/markdownToHtmlSpec.ts b/test/Core/markdownToHtmlSpec.ts
index 57d03723a42..4050bf8adcd 100644
--- a/test/Core/markdownToHtmlSpec.ts
+++ b/test/Core/markdownToHtmlSpec.ts
@@ -1,15 +1,9 @@
import registerCustomComponentTypes from "../../lib/ReactViews/Custom/registerCustomComponentTypes";
import markdownToHtml from "../../lib/Core/markdownToHtml";
-import Terria from "../../lib/Models/Terria";
import CustomComponent from "../../lib/ReactViews/Custom/CustomComponent";
describe("markdownToHtml", function () {
- let terria: Terria;
-
beforeEach(function () {
- terria = new Terria({
- baseUrl: "./"
- });
registerCustomComponentTypes();
});
it("correctly injects terria's custom tooltips", function () {
diff --git a/test/Map/TableColumnSpec.js b/test/Map/TableColumnSpec.js
deleted file mode 100644
index eb3d1981b7e..00000000000
--- a/test/Map/TableColumnSpec.js
+++ /dev/null
@@ -1,288 +0,0 @@
-"use strict";
-
-var JulianDate = require("terriajs-cesium/Source/Core/JulianDate").default;
-var TableColumn = require("../../lib/Map/TableColumn");
-var VarType = require("../../lib/Map/VarType");
-var VarSubType = require("../../lib/Map/VarSubType");
-
-describe("TableColumn", function () {
- it("can make a new object and detect scalar type", function () {
- // Use a copy of data to make the column, because knockout adds stuff to data.
- // Also, test a "slice" of the column's values, to remove knockout stuff.
- var data = [1, 3, 4];
- var tableColumn = new TableColumn("x", data.slice());
- expect(tableColumn.name).toEqual("x");
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.type).toEqual(VarType.SCALAR);
- });
-
- it("treats null, NA and hyphens as null in numeric data", function () {
- var data = [1, "NA", 4, "-", null, 3];
- var tableColumn = new TableColumn("x", data.slice());
- expect(tableColumn.name).toEqual("x");
- expect(tableColumn.values.slice()).toEqual([1, null, 4, null, null, 3]);
- expect(tableColumn.type).toEqual(VarType.SCALAR);
- });
-
- it("replaces null values before generating numericalValues", function () {
- var data = [0, 0, 0];
- var tableColumn = new TableColumn("x", data.slice(), {
- replaceWithNullValues: [0]
- });
- expect(tableColumn.numericalValues.slice()).toEqual([]);
- });
-
- it("treats hyphens, blanks and NA as strings in string data", function () {
- var data = ["%", "-", "!", "NA", ""];
- var tableColumn = new TableColumn("x", data.slice());
- expect(tableColumn.name).toEqual("x");
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.type).toEqual(VarType.ENUM);
- });
-
- it("provides a null index for a null value in string data", function () {
- var data = ["small", "medium", null, "big"];
- var tableColumn = new TableColumn("size", data.slice());
- expect(tableColumn.type).toEqual(VarType.ENUM);
- expect(tableColumn.isEnum).toBe(true);
- expect(tableColumn.values[1]).not.toBe(null);
- expect(tableColumn.values[2]).toBe(null);
- });
-
- it("ignores missing values when calculating min/max", function () {
- var data = [130.3, 131.3, null, 133.3];
- var tableColumn = new TableColumn("lat", data.slice());
- expect(tableColumn.maximumValue).toBe(133.3);
- expect(tableColumn.minimumValue).toBe(130.3);
- });
-
- it("can detect latitude type", function () {
- var data = [30.3, 31.3, 33.3];
- var tableColumn = new TableColumn("lat", data.slice());
- expect(tableColumn.type).toEqual(VarType.LAT);
- });
-
- it("can detect longitude type", function () {
- var data = [130.3, 131.3, 133.3];
- var tableColumn = new TableColumn("lon", data.slice());
- expect(tableColumn.type).toEqual(VarType.LON);
- });
-
- it("can detect address type", function () {
- var data = ["7 London Circuit Canberra City ACT 2601"];
- var tableColumn = new TableColumn("address", data);
- expect(tableColumn.type).toEqual(VarType.ADDR);
- });
-
- it("can detect time type from yyyy-mm-dd", function () {
- // Dates in this format are interpreted as midnight _UTC_ on the date.
- var data = ["2016-01-03", null, "2016-01-04"];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
-
- var expected = JulianDate.toDate(JulianDate.fromIso8601("2016-01-03"));
- expect(tableColumn.dates[0]).toEqual(expected);
- });
-
- it("can detect time type from dd-mm-yyyy", function () {
- // Dates in this format are interpreted as midnight _local time_ on the date.
- var data = ["31-12-2015", "04-01-2016", null];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[1].getDate()).toEqual(4);
- expect(tableColumn.dates[1].getMonth()).toEqual(0); // January is month 0
- expect(tableColumn.dates[1].getFullYear()).toEqual(2016);
- });
-
- it("can detect time type from mm-dd-yyyy", function () {
- // Dates in this format are interpreted as midnight _local time_ on the date.
- var data = ["12-31-2015", "01-04-2016", null];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[1].getDate()).toEqual(4);
- expect(tableColumn.dates[1].getMonth()).toEqual(0); // January is month 0
- expect(tableColumn.dates[1].getFullYear()).toEqual(2016);
- });
-
- it("can detect ISO8601 UTC time type", function () {
- var data = ["2016-01-03T12:15:59.1234Z", null, "2016-01-03T12:25:00Z"];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[0].getUTCDate()).toEqual(3);
- expect(tableColumn.dates[0].getUTCMonth()).toEqual(0); // January is month 0
- expect(tableColumn.dates[0].getUTCFullYear()).toEqual(2016);
- expect(tableColumn.dates[0].getUTCHours()).toEqual(12);
- expect(tableColumn.dates[0].getUTCMinutes()).toEqual(15);
- expect(tableColumn.dates[0].getUTCSeconds()).toEqual(59);
- expect(tableColumn.dates[0].getUTCMilliseconds()).toEqual(123);
- });
-
- it("can detect time type and year subtype from yyyy", function () {
- var data = ["2010", "2011", "2012", null, "2013"];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.subtype).toEqual(VarSubType.YEAR);
- expect(tableColumn.values.slice()).toEqual(data);
- // don't test equality using new Date() because different browsers handle timezones differently
- // so just check the date is right.
- expect(tableColumn.dates[0].getDate()).toEqual(1);
- expect(tableColumn.dates[0].getMonth()).toEqual(0); // January is month 0
- expect(tableColumn.dates[0].getFullYear()).toEqual(2010);
- });
-
- it("can detect time type from yyyy-mm", function () {
- // Dates in this format are interpreted as midnight _UTC_ on the date.
- var data = ["2010-01", "2010-02", "2010-03", null, "2010-04"];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- var expected = JulianDate.toDate(JulianDate.fromIso8601("2010-02"));
- expect(tableColumn.dates[1]).toEqual(expected);
- });
-
- // This format can actually work, but we don't want to encourage it.
- // it('can detect time type from yyyy/mm/dd h:mm:ss', function() {
- // var data = ['2010/02/12 12:34:56', '2010/02/13 1:23:45'];
- // var tableColumn = new TableColumn('date', data);
- // expect(tableColumn.type).toEqual(VarType.TIME);
- // expect(tableColumn.values).toEqual(data);
- // expect(tableColumn.dates[1].getDate()).toEqual(13);
- // expect(tableColumn.dates[1].getMonth()).toEqual(1); // January is month 0
- // expect(tableColumn.dates[1].getFullYear()).toEqual(2010);
- // expect(tableColumn.dates[1].getHours()).toEqual(1);
- // expect(tableColumn.dates[1].getMinutes()).toEqual(23);
- // expect(tableColumn.dates[1].getSeconds()).toEqual(45);
- // });
-
- it("can detect time type from yyyy-mm-dd h:mm", function () {
- var data = ["2010-02-12 12:34", "2010-02-13 1:23", null];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[1].getDate()).toEqual(13);
- expect(tableColumn.dates[1].getMonth()).toEqual(1); // January is month 0
- expect(tableColumn.dates[1].getFullYear()).toEqual(2010);
- expect(tableColumn.dates[1].getHours()).toEqual(1);
- expect(tableColumn.dates[1].getMinutes()).toEqual(23);
- expect(tableColumn.dates[1].getSeconds()).toEqual(0);
- });
-
- it("can detect time type from yyyy-mm-dd h:mm:ss", function () {
- var data = ["2010-02-12 12:34:56", "2010-02-13 1:23:45", null];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[1].getDate()).toEqual(13);
- expect(tableColumn.dates[1].getMonth()).toEqual(1); // January is month 0
- expect(tableColumn.dates[1].getFullYear()).toEqual(2010);
- expect(tableColumn.dates[1].getHours()).toEqual(1);
- expect(tableColumn.dates[1].getMinutes()).toEqual(23);
- expect(tableColumn.dates[1].getSeconds()).toEqual(45);
- });
-
- it("can detect time type from yyyy-Qx", function () {
- var data = ["2010-Q1", "2010-Q2", "2010-Q3", null, "2010-Q4"];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.values.slice()).toEqual(data);
- expect(tableColumn.dates[1].getDate()).toEqual(1);
- expect(tableColumn.dates[1].getMonth()).toEqual(3); // January is month 0
- expect(tableColumn.dates[1].getFullYear()).toEqual(2010);
- });
-
- it("can detect year subtype using year title", function () {
- var data = ["1066", "1776", "1788", "1901", null, "2220"];
- var tableColumn = new TableColumn("year", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.subtype).toEqual(VarSubType.YEAR);
- });
-
- it("detects years from numerical data in a column named time", function () {
- var data = [730, 1230, null, 130];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.subtype).toEqual(VarSubType.YEAR);
- expect(tableColumn.values.slice()).toEqual(data);
- });
-
- it("can handle missing times", function () {
- var data = ["2016-01-03T12:15:59.1234Z", "-", "2016-01-04T12:25:00Z", null];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.TIME);
- expect(tableColumn.dates[0].getUTCDate()).toEqual(3);
- expect(tableColumn.dates[1]).toBeUndefined();
- expect(tableColumn.dates[2].getUTCDate()).toEqual(4);
- });
-
- it("treats numerical data >= 9999 in a column named time as scalars", function () {
- var data = [9999, 1230, null, 130];
- var tableColumn = new TableColumn("date", data.slice());
- expect(tableColumn.type).toEqual(VarType.SCALAR);
- expect(tableColumn.values.slice()).toEqual(data);
- });
-
- it("can detect tag type from ", function () {
- var data = [' ', ' '];
- var tableColumn = new TableColumn("image", data.slice());
- expect(tableColumn.type).toEqual(VarType.TAG);
- });
-
- it("can detect tag type from ", function () {
- var data = [" ", " "];
- var tableColumn = new TableColumn("bar", data);
- expect(tableColumn.type).toEqual(VarType.TAG);
- });
-
- it("can detect tag type from ", function () {
- var data = ["
Foo
", "
Bar
"];
- var tableColumn = new TableColumn("foo", data);
- expect(tableColumn.type).toEqual(VarType.TAG);
- });
-
- it("does not use tag type for <<...>>", function () {
- var data = ["<
>", "<>"];
- var tableColumn = new TableColumn("who", data);
- expect(tableColumn.type).toEqual(VarType.ENUM);
- });
-
- it("does not use tag type for ", function () {
- var data = ["", ""];
- var tableColumn = new TableColumn("fee", data);
- expect(tableColumn.type).toEqual(VarType.ENUM);
- });
-
- it("can sum three columns from array", function () {
- var tableColumns = [
- new TableColumn("one", [10, 1]),
- new TableColumn("two", [25, 2.5]),
- new TableColumn("three", [-2, 6])
- ];
- var result = TableColumn.sumValues(tableColumns);
- var target = [10 + 25 - 2, 1 + 2.5 + 6];
- expect(result).toEqual(target);
- });
-
- it("can sum three columns as arguments", function () {
- var result = TableColumn.sumValues(
- new TableColumn("one", [10, 1]),
- new TableColumn("two", [25, 2.5]),
- new TableColumn("three", [-2, 6])
- );
- var target = [10 + 25 - 2, 1 + 2.5 + 6];
- expect(result).toEqual(target);
- });
-
- it("can divide two columns' values", function () {
- var result = TableColumn.divideValues(
- new TableColumn("num", [40, 3, 8]),
- new TableColumn("den", [10, 6, 0]),
- "bad"
- );
- var target = [4, 0.5, "bad"];
- expect(result).toEqual(target);
- });
-});
diff --git a/test/Map/TableStructureSpec.js b/test/Map/TableStructureSpec.js
deleted file mode 100644
index 55b4b24fc6b..00000000000
--- a/test/Map/TableStructureSpec.js
+++ /dev/null
@@ -1,921 +0,0 @@
-"use strict";
-
-var JulianDate = require("terriajs-cesium/Source/Core/JulianDate").default;
-var TableStructure = require("../../lib/Map/TableStructure");
-var TimeInterval = require("terriajs-cesium/Source/Core/TimeInterval").default;
-var VarType = require("../../lib/Map/VarType");
-
-var separator = ",";
-var decimalPoint = ".";
-if (typeof Intl === "object" && typeof Intl.NumberFormat === "function") {
- separator = Intl.NumberFormat().format(1000)[1];
- decimalPoint = Intl.NumberFormat().format(0.5)[1];
-}
-
-describe("TableStructure", function () {
- it("can read from json object", function () {
- // Use a copy of data to make the column, because knockout adds stuff to data.
- // Also, test a "slice" of the column's values, to remove knockout stuff.
- var data = [
- ["x", "y"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data.slice());
- expect(tableStructure.columns.length).toEqual(2);
- expect(tableStructure.columns[0].name).toEqual("x");
- expect(tableStructure.columns[0].values.slice()).toEqual([1, 3, 4]);
- expect(tableStructure.columns[1].name).toEqual("y");
- expect(tableStructure.columns[1].values.slice()).toEqual([5, 8, -3]);
- });
-
- it("can read from csv string", function () {
- var csvString = "x,y\r\n1,5\r\n3,8\r\n4,-3\r\n";
- var tableStructure = TableStructure.fromCsv(csvString);
- expect(tableStructure.columns.length).toEqual(2);
- expect(tableStructure.columns[0].name).toEqual("x");
- expect(tableStructure.columns[0].values.slice()).toEqual([1, 3, 4]);
- expect(tableStructure.columns[1].name).toEqual("y");
- expect(tableStructure.columns[1].values.slice()).toEqual([5, 8, -3]);
- });
-
- it("can read from json object into existing structure", function () {
- var data = [
- ["x", "y"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = new TableStructure();
- tableStructure.loadFromJson(data);
- expect(tableStructure.columns.length).toEqual(2);
- expect(tableStructure.columns[0].name).toEqual("x");
- expect(tableStructure.columns[0].values.slice()).toEqual([1, 3, 4]);
- expect(tableStructure.columns[1].name).toEqual("y");
- expect(tableStructure.columns[1].values.slice()).toEqual([5, 8, -3]);
- });
-
- it("can read from csv string into existing structure", function () {
- var csvString = "x,y\r\n1,5\r\n3,8\r\n4,-3\r\n";
- var tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns.length).toEqual(2);
- expect(tableStructure.columns[0].name).toEqual("x");
- expect(tableStructure.columns[0].values.slice()).toEqual([1, 3, 4]);
- expect(tableStructure.columns[1].name).toEqual("y");
- expect(tableStructure.columns[1].values.slice()).toEqual([5, 8, -3]);
- });
-
- it("can convert to ArrayOfColumns", function () {
- var data = [
- ["x", "y"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data);
- var columns = tableStructure.toArrayOfColumns();
- expect(columns.length).toEqual(2);
- expect(columns[0]).toEqual(["x", 1, 3, 4]);
- expect(columns[1]).toEqual(["y", 5, 8, -3]);
- });
-
- it("can convert to ArrayOfRows", function () {
- var data = [
- ["x", "y"],
- ["1", "5"],
- ["3", "8"],
- ["4", "-3"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- var rows = tableStructure.toArrayOfRows();
- expect(rows.length).toEqual(4);
- expect(rows).toEqual(data);
- });
-
- it("can convert to ArrayOfRows with formatting", function () {
- var data = [
- ["x", "y"],
- [1.678, 9.883],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- x: { format: { maximumFractionDigits: 0 } },
- y: {
- name: "new y (,000)",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var target = [
- ["x", "new y (,000)"],
- ["2", "9.9"],
- ["54321", "12" + separator + "345"],
- ["4", "-3"]
- ];
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var rows = tableStructure.toArrayOfRows();
- expect(rows.length).toEqual(4);
- expect(rows).toEqual(target);
- });
-
- it("can convert to ArrayOfRows with formatting and quotes if containing commas", function () {
- var data = [
- ["x", "y"],
- [1.678, 9.883],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- x: { format: { maximumFractionDigits: 0 } },
- y: {
- name: "new y (,000)",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var target = [
- ["x", '"new y (,000)"'],
- ["2", "9.9"],
- ["54321", '"12' + separator + '345"'],
- ["4", "-3"]
- ];
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var rows = tableStructure.toArrayOfRows(undefined, undefined, true, true); // 4th argument requests the quotes.
- expect(rows.length).toEqual(4);
- expect(rows).toEqual(target);
- });
-
- it("can convert to ArrayOfRows with formatting and quotes if containing quotes", function () {
- var data = [
- ["x", "y"],
- [1.678, 9.883],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- x: { format: { maximumFractionDigits: 0 } },
- y: {
- name: 'new y ("000")',
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var target = [
- ["x", '"new y (""000"")"'],
- ["2", "9.9"],
- ["54321", '"12' + separator + '345"'],
- ["4", "-3"]
- ];
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var rows = tableStructure.toArrayOfRows(undefined, undefined, true, true); // 4th argument requests the quotes.
- expect(rows.length).toEqual(4);
- expect(rows).toEqual(target);
- });
-
- it("can convert to csv", function () {
- var data = [
- ["lat", "y"],
- [1.678, 9.883],
- [54321, 12345],
- [4, -3]
- ];
- var tableStructure = new TableStructure();
- tableStructure = tableStructure.loadFromJson(data);
- var csvString = tableStructure.toCsvString();
- expect(csvString).toEqual("lat,y\n1.678,9.883\n54321,12345\n4,-3");
- });
-
- it("can create a data URI", function () {
- var data = [
- ["lat", "y"],
- [1.6, -9.8]
- ];
- var tableStructure = new TableStructure();
- // From json
- tableStructure = tableStructure.loadFromJson(data);
- var uri = tableStructure.toDataUri();
- expect(uri).toEqual("data:attachment/csv,lat%2Cy%0A1.6%2C-9.8");
- // From csv
- var csvString = "lat,y\n1.6,-9.8";
- tableStructure.loadFromCsv(csvString);
- uri = tableStructure.toDataUri();
- expect(uri).toEqual("data:attachment/csv,lat%2Cy%0A1.6%2C-9.8");
- });
-
- it("can convert to row objects", function () {
- var data = [
- ["lat", "y"],
- [1, 5.12345],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data);
- var rowObjects = tableStructure.toRowObjects();
- expect(rowObjects.length).toEqual(3);
- // Scalar fields are converted to strings using toLocaleString, but not lat/lon.
- // We could convert lat/lons too, if there's a reason to do it.
- expect(rowObjects[0]).toEqual({ lat: 1, y: "5.12345" });
- expect(rowObjects[1]).toEqual({ lat: 3, y: "8" });
- expect(rowObjects[2]).toEqual({ lat: 4, y: "-3" });
- });
-
- it("can convert to string and number row objects", function () {
- var data = [
- ["x", "y"],
- [1.678, -9.883],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- x: { format: { maximumFractionDigits: 0 } },
- y: {
- name: "newy",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var rowObjects = tableStructure.toStringAndNumberRowObjects();
- expect(rowObjects.length).toEqual(3);
- expect(rowObjects[0]).toEqual({
- string: { x: "2", newy: "-9" + decimalPoint + "9" },
- number: { x: 1.678, newy: -9.883 }
- });
- expect(rowObjects[1]).toEqual({
- string: { x: "54321", newy: "12" + separator + "345" },
- number: { x: 54321, newy: 12345 }
- });
- });
-
- it("can convert to point arrays", function () {
- var data = [
- ["a", "b", "c"],
- [1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]
- ];
- var tableStructure = TableStructure.fromJson(data);
- var xy = tableStructure.toPointArrays();
- expect(xy.length).toEqual(2);
- expect(xy[0]).toEqual([
- { x: 1, y: 2 },
- { x: 4, y: 5 },
- { x: 7, y: 8 }
- ]);
- expect(xy[1]).toEqual([
- { x: 1, y: 3 },
- { x: 4, y: 6 },
- { x: 7, y: 9 }
- ]);
- });
-
- it("can get column names", function () {
- var data = [
- ["lat", "y"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data);
- expect(tableStructure.getColumnNames()).toEqual(["lat", "y"]);
- });
-
- it("can get column with name", function () {
- var data = [
- ["x", "y"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data);
- expect(tableStructure.getColumnWithName("y")).toEqual(
- tableStructure.columns[1]
- );
- expect(tableStructure.getColumnWithName("z")).toBeUndefined();
- });
-
- it("sets column types", function () {
- var data = [
- ["x", "lat"],
- [1, 5],
- [3, 8],
- [4, -3]
- ];
- var tableStructure = TableStructure.fromJson(data);
- expect(tableStructure.columnsByType[VarType.SCALAR].length).toEqual(1);
- expect(tableStructure.columnsByType[VarType.SCALAR][0].name).toEqual("x");
- expect(tableStructure.columnsByType[VarType.LAT].length).toEqual(1);
- expect(tableStructure.columnsByType[VarType.LAT][0].name).toEqual("lat");
- });
-
- it("counts the final row of CSV files with no trailing linefeed(s)", function () {
- var csvString = "postcode,value\n0800,1\n0885,2";
- var tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
-
- csvString = csvString + "\n";
- tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
-
- // The ABS returns a csv data file for Australia with two final linefeeds.
- csvString = csvString + "\n";
- tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
- });
-
- it("ignores final blank rows of CSV files", function () {
- var csvString = "postcode,value\n0800,1,\n0885,2,";
- var tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
-
- csvString = csvString + "\n";
- tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
-
- csvString = csvString + "\n\n\n\n\n";
- tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].values.length).toEqual(2);
- expect(tableStructure.columns[1].values.length).toEqual(2);
- });
-
- it("can read csv string where column names are numbers", function () {
- var csvString = "1,2\n9,8\n7,6";
- var tableStructure = new TableStructure();
- tableStructure.loadFromCsv(csvString);
- expect(tableStructure.columns[0].name).toEqual("1");
- expect(tableStructure.columns[1].name).toEqual("2");
- });
-
- it("can describe rows with dates with and without timezones nicely", function () {
- var csvString =
- "date,value\r\n2015-10-15T12:34:56,5\r\n2015-10-02T12:34:56Z,8\r\n2015-11-03\r\n";
- var tableStructure = TableStructure.fromCsv(csvString);
- var htmls = tableStructure.toRowDescriptions();
- expect(htmls[0]).toContain("Thu Oct 15 2015 12:34:56"); // Thu 15 Oct would be nicer outside USA.
- expect(htmls[0]).not.toContain("2015-10-15T12:34:56");
- var expectedDate1 = JulianDate.toDate(
- JulianDate.fromIso8601("2015-10-02T12:34:56Z")
- );
- expect(htmls[1]).toContain("" + expectedDate1);
- expect(htmls[1]).not.toContain("2015-10-02T12:34:56");
- expect(htmls[2]).toContain(">2015-11-03<"); // No time is added when only the date is given.
- });
-
- it("can describe rows with formatting", function () {
- var data = [
- ["x", "y"],
- [1.678, 5.123],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- y: {
- name: "new y",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var htmls = tableStructure.toRowDescriptions();
- expect(htmls[0]).toContain("new y");
- expect(htmls[0]).toContain("1.678");
- expect(htmls[0]).toContain("5.1");
- expect(htmls[0]).not.toContain("5.12");
- expect(htmls[1]).toContain("54321");
- expect(htmls[1]).toContain("12" + separator + "345");
- });
-
- it("can tell if it has address data", function () {
- var data = [
- ["x", "y", "Address"],
- [1.678, 5.123, "25 Gozzard Street, GUNGAHLIN TOWN CENTRE, ACT"],
- [54321, 12345, "137 Reed Street, TUGGERANONG, ACT"],
- [4, -3, "81 Mildura Street, FYSHWICK, ACT"]
- ];
- var options = {
- columnOptions: {
- y: {
- name: "new y",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- expect(tableStructure.hasAddress).toBe(true);
-
- var dataNoAddr = [
- ["x", "y"],
- [1.678, 5.123],
- [54321, 12345],
- [4, -3]
- ];
- var optionsNoAddr = {
- columnOptions: {
- y: {
- name: "new y",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var tableStructureNoAddr = new TableStructure("foo", optionsNoAddr);
- tableStructureNoAddr = tableStructure.loadFromJson(dataNoAddr);
- expect(tableStructureNoAddr.hasAddress).toBe(false);
- });
-
- it("can get feature id mapping", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2],
- [1971, "A", 67.8, 1.2],
- [1972, "B", 68.2, 2.2]
- ];
- var options = { idColumnNames: ["id"] };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var map = tableStructure.getIdMapping();
- expect(map["A"]).toEqual([0, 2]);
- expect(map["B"]).toEqual([1, 3]);
- });
-
- it("can handle idColumnNames = []", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2],
- [1971, "A", 67.8, 1.2],
- [1972, "B", 68.2, 2.2]
- ];
- var options = { idColumnNames: [] };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(data);
- var map = tableStructure.getIdMapping();
- expect(map).toEqual({});
- });
-
- it("can append a table", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2]
- ];
- var dat2 = [
- ["year", "id", "lat", "lon"],
- [1980, "C", 16.8, 5.2],
- [1981, "D", 16.2, 5.2]
- ];
- var table1 = new TableStructure("foo");
- var table2 = new TableStructure("bar");
- table1 = table1.loadFromJson(data);
- table2 = table2.loadFromJson(dat2);
- table1.append(table2);
- expect(table1.columns[0].values.slice()).toEqual([1970, 1971, 1980, 1981]);
- expect(table1.columns[1].values.slice()).toEqual(["A", "B", "C", "D"]);
- });
-
- it("can append part of a table", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2]
- ];
- var dat2 = [
- ["year", "id", "lat", "lon"],
- [1980, "C", 16.8, 5.2],
- [1981, "D", 16.2, 5.2],
- [1982, "E", 16, 5],
- [1983, "F", 15, 6]
- ];
- var table1 = new TableStructure("foo");
- var table2 = new TableStructure("bar");
- table1 = table1.loadFromJson(data);
- table2 = table2.loadFromJson(dat2);
- table1.append(table2, [1, 3]);
- expect(table1.columns[0].values.slice()).toEqual([1970, 1971, 1981, 1983]);
- expect(table1.columns[1].values.slice()).toEqual(["A", "B", "D", "F"]);
- });
-
- it("can replace rows", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2]
- ];
- var dat2 = [
- ["year", "id", "lat", "lon"],
- [1980, "C", 16.8, 5.2],
- [1981, "D", 16.2, 5.2]
- ];
- var table1 = new TableStructure("foo");
- var table2 = new TableStructure("bar");
- table1 = table1.loadFromJson(data);
- table2 = table2.loadFromJson(dat2);
- table1.replaceRows(table2, { 1: 0 });
- expect(table1.columns[0].values.slice()).toEqual([1970, 1980]);
- expect(table1.columns[1].values.slice()).toEqual(["A", "C"]);
- });
-
- it("can merge tables with dates", function () {
- var data = [
- ["year", "id", "lat", "lon"],
- [1970, "A", 16.8, 5.2],
- [1971, "B", 16.2, 5.2]
- ];
- var dat2 = [
- ["year", "id", "lat", "lon"],
- [1975, "C", 15, 5.5],
- [1970, "A", 12, 8],
- [1971, "A", 13, 9]
- ];
- var options = { idColumnNames: ["id"] };
- var table1 = new TableStructure("foo", options);
- var table2 = new TableStructure("bar"); // Only uses idColumnNames on table1.
- table1 = table1.loadFromJson(data);
- table2 = table2.loadFromJson(dat2);
- table1.setActiveTimeColumn(0);
- table1.columns[1].isActive = true;
- table1.columns[1].color = "blue";
- table1.merge(table2);
- expect(table1.columns[0].values.slice()).toEqual([1970, 1971, 1975, 1971]);
- expect(table1.activeTimeColumn.dates.length).toEqual(4); // ie. activeTimeColumn updates too.
- expect(table1.columns[1].values.slice()).toEqual(["A", "B", "C", "A"]);
- expect(table1.columns[2].values.slice()).toEqual([12, 16.2, 15, 13]);
- expect(table1.columns[1].isActive).toBe(true); // ie. Don't lose options on the columns.
- expect(table1.columns[1].color).toEqual("blue");
- });
-
- it("can merge tables without dates", function () {
- var data = [
- ["id", "lat", "lon"],
- ["A", 16.8, 5.2],
- ["B", 16.2, 5.2]
- ];
- var dat2 = [
- ["id", "lat", "lon"],
- ["A", 12, 8],
- ["C", 15, 5.5]
- ];
- var options = { idColumnNames: ["id"] };
- var table1 = new TableStructure("foo", options);
- var table2 = new TableStructure("bar"); // Only uses idColumnNames on table1.
- table1 = table1.loadFromJson(data);
- table2 = table2.loadFromJson(dat2);
- table1.merge(table2);
- expect(table1.columns[0].values.slice()).toEqual(["A", "B", "C"]);
- expect(table1.columns[1].values.slice()).toEqual([12, 16.2, 15]);
- });
-
- it("can add columns", function () {
- var dataNoAddr = [
- ["x", "y"],
- [1.678, 5.123],
- [54321, 12345],
- [4, -3]
- ];
- var options = {
- columnOptions: {
- y: {
- name: "new y",
- format: { useGrouping: true, maximumFractionDigits: 1 }
- }
- }
- };
- var tableStructure = new TableStructure("foo", options);
- tableStructure = tableStructure.loadFromJson(dataNoAddr);
- var longValues = [44.0, 55.0, 66.0];
- var latValues = [11.0, 22.0, 33.0];
- expect(tableStructure.hasLatitudeAndLongitude).toBe(false);
- tableStructure.addColumn("lat", latValues);
- tableStructure.addColumn("lon", longValues);
- expect(tableStructure.hasLatitudeAndLongitude).toBe(true);
- expect(tableStructure.columns[VarType.LAT].values).toBe(latValues);
- expect(tableStructure.columns[VarType.LON].values).toBe(longValues);
- });
-
- it("can sort columns", function () {
- var data = [
- ["x", "y", "z"],
- [3, 5, "a"],
- [1, 8, "c"],
- [4, -3, "b"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.sortBy(tableStructure.getColumnWithName("x"));
- expect(tableStructure.getColumnWithName("x").values.slice()).toEqual([
- 1, 3, 4
- ]);
- expect(tableStructure.getColumnWithName("y").values.slice()).toEqual([
- 8, 5, -3
- ]);
- expect(tableStructure.getColumnWithName("z").values.slice()).toEqual([
- "c",
- "a",
- "b"
- ]);
- tableStructure.sortBy(tableStructure.getColumnWithName("z"));
- expect(tableStructure.getColumnWithName("x").values.slice()).toEqual([
- 3, 4, 1
- ]);
- expect(tableStructure.getColumnWithName("y").values.slice()).toEqual([
- 5, -3, 8
- ]);
- expect(tableStructure.getColumnWithName("z").values.slice()).toEqual([
- "a",
- "b",
- "c"
- ]);
- tableStructure.sortBy(
- tableStructure.getColumnWithName("x"),
- function (a, b) {
- return b - a;
- }
- ); // descending
- expect(tableStructure.getColumnWithName("x").values.slice()).toEqual([
- 4, 3, 1
- ]);
- expect(tableStructure.getColumnWithName("y").values.slice()).toEqual([
- -3, 5, 8
- ]);
- expect(tableStructure.getColumnWithName("z").values.slice()).toEqual([
- "b",
- "a",
- "c"
- ]);
- });
-
- it("can sort columns by date, even with null dates", function () {
- // Note the last date occurs before the first, but a string compare would disagree.
- var data = [
- ["date", "v"],
- ["2010-06-20T10:00:00.0+1000", "a"],
- ["2010-06-19T10:00:00.0+1000", "b"],
- [null, "n"],
- ["2010-06-20T10:00:00.0+1100", "c"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.sortBy(tableStructure.columns[0]);
- expect(tableStructure.columns[1].values.slice()).toEqual([
- "b",
- "c",
- "a",
- "n"
- ]);
- });
-
- it("can calculate finish dates", function () {
- var data = [["date"], ["2016-01-03T12:15:00Z"], ["2016-01-03T12:15:30Z"]];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.setActiveTimeColumn();
- expect(tableStructure.finishJulianDates).toEqual([
- JulianDate.fromIso8601("2016-01-03T12:15:30Z"),
- JulianDate.fromIso8601("2016-01-03T12:16:00Z") // Final one should have the average spacing, 30 sec.
- ]);
- });
-
- it("can calculate sub-second finish dates", function () {
- var data = [
- ["date"],
- ["2016-01-03T12:15:00Z"],
- ["2016-01-03T12:15:00.4Z"],
- ["2016-01-03T12:15:01Z"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.setActiveTimeColumn();
- expect(tableStructure.finishJulianDates).toEqual([
- JulianDate.fromIso8601("2016-01-03T12:15:00.40Z"),
- JulianDate.fromIso8601("2016-01-03T12:15:01Z"),
- JulianDate.fromIso8601("2016-01-03T12:15:01.5Z") // Average spacing is 0.5 second.
- ]);
- });
-
- it("supports displayDuration", function () {
- var data = [["date"], ["2016-01-03"], ["2016-01-04"], ["2016-01-05"]];
- var sevenDaysInMinutes = 60 * 24 * 7;
- var tableStructure = new TableStructure("test", {
- displayDuration: sevenDaysInMinutes
- });
- TableStructure.fromJson(data, tableStructure);
- tableStructure.setActiveTimeColumn();
- var interval = tableStructure.timeIntervals[0];
- expect(
- TimeInterval.contains(interval, JulianDate.fromIso8601("2016-01-09"))
- ).toBe(true);
- expect(
- TimeInterval.contains(interval, JulianDate.fromIso8601("2016-01-11"))
- ).toBe(false);
- var durationInSeconds = JulianDate.secondsDifference(
- interval.stop,
- interval.start
- );
- expect(durationInSeconds).toEqual(sevenDaysInMinutes * 60);
- });
-
- it("uses start_date and end_date", function () {
- // Note these end dates overlap (12:15:00-12:16:10, 12:15:30-12:16:40).
- var data = [
- ["start_date", "end_date"],
- ["2016-01-03T12:15:00Z", "2016-01-03T12:16:10Z"],
- ["2016-01-03T12:15:30Z", "2016-01-03T12:16:40Z"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.setActiveTimeColumn();
- expect(tableStructure.finishJulianDates).toEqual([
- JulianDate.fromIso8601("2016-01-03T12:16:10Z"),
- JulianDate.fromIso8601("2016-01-03T12:16:40Z")
- ]);
- });
-
- it("calculates id-specific date periods", function () {
- // A and B both have two two-day observations, but they are interspersed.
- // Without an id column, they would have one-day observations.
- var data = [
- ["date", "id"],
- ["2016-01-01T00:00:00Z", "A"],
- ["2016-01-02T00:00:00Z", "B"],
- ["2016-01-03T00:00:00Z", "A"],
- ["2016-01-04T00:00:00Z", "B"]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.idColumnNames = ["id"];
- tableStructure.shaveSeconds = 0;
- tableStructure.setActiveTimeColumn();
- expect(tableStructure.finishJulianDates).toEqual([
- JulianDate.fromIso8601("2016-01-03T00:00:00Z"),
- JulianDate.fromIso8601("2016-01-04T00:00:00Z"),
- JulianDate.fromIso8601("2016-01-05T00:00:00Z"),
- JulianDate.fromIso8601("2016-01-06T00:00:00Z")
- ]);
- });
-
- it("can add feature rows at start and end dates", function () {
- var data = [
- ["date", "id", "value"],
- ["2016-01-01T00:00:00Z", "A", 10],
- ["2016-01-02T00:00:00Z", "B", 15],
- ["2016-01-03T00:00:00Z", "A", 12],
- ["2016-01-04T00:00:00Z", "B", 17]
- ];
- var tableStructure = TableStructure.fromJson(data);
- tableStructure.idColumnNames = ["id"];
- tableStructure.columns =
- tableStructure.getColumnsWithFeatureRowsAtStartAndEndDates(
- "date",
- "value"
- );
- tableStructure.setActiveTimeColumn();
- expect(tableStructure.columns[1].values.slice()).toEqual([
- "A",
- "B",
- "B",
- "A",
- "B",
- "A"
- ]);
- expect(tableStructure.columns[2].values.slice()).toEqual([
- 10,
- null,
- 15,
- 12,
- 17,
- null
- ]);
- expect(tableStructure.activeTimeColumn.julianDates).toEqual([
- JulianDate.fromIso8601("2016-01-01T00:00:00Z"), // A, 10
- JulianDate.fromIso8601("2016-01-01T00:00:00Z"), // The new B, null
- JulianDate.fromIso8601("2016-01-02T00:00:00Z"), // B, 15
- JulianDate.fromIso8601("2016-01-03T00:00:00Z"), // A, 12
- JulianDate.fromIso8601("2016-01-04T00:00:00Z"), // B, 17
- JulianDate.fromIso8601("2016-01-04T00:00:00Z") // The new A, null
- ]);
- });
-
- describe("Time slider initial time as specified by initialTimeSource ", function () {
- // Future developers take note: some of these tests will stop working sometime after August 3015.
- it('should be start if "start" set', function () {
- var tableStructure = new TableStructure("test", {
- initialTimeSource: "start"
- });
- // Note: Specifying the time in this way means that the end date will be after 2015-08-09, but since we don't care particularly about the end date this is enough precision for this test.
- var data = [
- ["date"],
- ["2013-08-07T00:00:00.00Z"],
- ["2015-08-09T00:00:00.00Z"]
- ];
- TableStructure.fromJson(data, tableStructure);
- tableStructure.setActiveTimeColumn();
-
- var currentTime = JulianDate.toIso8601(
- tableStructure.clock.currentTime,
- 3
- );
- // Do not compare time, because on some systems the second could have ticked over between getting the two times.
- currentTime = currentTime.substr(0, 10);
- expect(currentTime).toBe("2013-08-07");
- });
-
- it('should be current time if "present" set', function () {
- var tableStructure = new TableStructure("test", {
- initialTimeSource: "present"
- });
- // Note: Specifying the time in this way means that the end date will be after 2015-08-09, but since we don't care particularly about the end date this is enough precision for this test.
- var data = [
- ["date"],
- ["2013-08-07T00:00:00.00Z"],
- ["3115-08-09T00:00:00.00Z"]
- ];
- TableStructure.fromJson(data, tableStructure);
- tableStructure.setActiveTimeColumn();
-
- var dateNow = new Date().toISOString();
- var currentTime = JulianDate.toIso8601(
- tableStructure.clock.currentTime,
- 3
- );
- // Do not compare time, because on some systems the second could have ticked over between getting the two times.
- dateNow = dateNow.substr(0, 10);
- currentTime = currentTime.substr(0, 10);
- expect(currentTime).toBe(dateNow);
- });
-
- it('should be last time if "end" set', function () {
- var tableStructure = new TableStructure("test", {
- initialTimeSource: "end",
- finalEndJulianDate: JulianDate.fromIso8601("2015-08-09T00:00:00.00Z")
- });
- var data = [["date"], ["2013-08-07T00:00:00.00Z"]];
- TableStructure.fromJson(data, tableStructure);
- tableStructure.setActiveTimeColumn();
-
- var currentTime = JulianDate.toIso8601(
- tableStructure.clock.currentTime,
- 3
- );
- // Do not compare time, because on some systems the second could have ticked over between getting the two times.
- currentTime = currentTime.substr(0, 10);
- expect(currentTime).toBe("2015-08-09");
- });
-
- it("should be set to date specified if date is specified", function () {
- var tableStructure = new TableStructure("test", {
- initialTimeSource: "2015-08-08T00:00:00.00Z"
- });
- // Note: Specifying the time in this way means that the end date will be after 2015-08-11, but since we don't care particularly about the end date this is enough precision for this test.
- var data = [
- ["date"],
- ["2013-08-07T00:00:00.00Z"],
- ["2015-08-11T00:00:00.00Z"]
- ];
- TableStructure.fromJson(data, tableStructure);
- tableStructure.setActiveTimeColumn();
-
- var currentTime = JulianDate.toIso8601(
- tableStructure.clock.currentTime,
- 3
- );
- // Do not compare time, because on some systems the second could have ticked over between getting the two times.
- currentTime = currentTime.substr(0, 10);
- expect(currentTime).toBe("2015-08-08");
- });
-
- it("should throw if a rubbish string is specified", function () {
- var tableStructure = new TableStructure("test", {
- initialTimeSource: "2015z08-08"
- });
- var data = [
- ["date"],
- ["2013-08-07T00:00:00.00Z"],
- ["2015-08-11T00:00:00.00Z"]
- ];
- TableStructure.fromJson(data, tableStructure);
-
- expect(function () {
- tableStructure.setActiveTimeColumn();
- }).toThrow();
- });
- });
-});
diff --git a/test/ModelMixins/DiffableMixinSpec.ts b/test/ModelMixins/DiffableMixinSpec.ts
index c9114dd9ef2..f5782695203 100644
--- a/test/ModelMixins/DiffableMixinSpec.ts
+++ b/test/ModelMixins/DiffableMixinSpec.ts
@@ -62,17 +62,17 @@ class TestDiffableItem extends DiffableMixin(
}
showDiffImage(
- firstDate: JulianDate,
- secondDate: JulianDate,
- diffStyleId: string
+ _firstDate: JulianDate,
+ _secondDate: JulianDate,
+ _diffStyleId: string
) {}
clearDiffImage() {}
getLegendUrlForStyle(
- diffStyleId: string,
- firstDate: JulianDate,
- secondDate: JulianDate
+ _diffStyleId: string,
+ _firstDate: JulianDate,
+ _secondDate: JulianDate
) {
return "test-legend-url";
}
diff --git a/test/ModelMixins/DiscretelyTimeVaryingMixinSpec.ts b/test/ModelMixins/DiscretelyTimeVaryingMixinSpec.ts
index 18502dddbb0..b235c8a4b32 100644
--- a/test/ModelMixins/DiscretelyTimeVaryingMixinSpec.ts
+++ b/test/ModelMixins/DiscretelyTimeVaryingMixinSpec.ts
@@ -23,10 +23,10 @@ describe("DiscretelyTimeVaryingMixin", () => {
await wmsItem.loadMapItems();
const years = wmsItem.objectifiedDates[20];
- expect(years.dates.length).toBe(1000);
+ expect(years.dates.length).toBe(10000);
expect(years.index[0]).toBe(2015);
const months = years[years.index[0]];
- expect(months.dates.length).toBe(1000);
+ expect(months.dates.length).toBe(10000);
expect(months.index[0]).toBe(3);
});
diff --git a/test/ModelMixins/TableMixinSpec.ts b/test/ModelMixins/TableMixinSpec.ts
index 256e51d3284..4e17baf4ebb 100644
--- a/test/ModelMixins/TableMixinSpec.ts
+++ b/test/ModelMixins/TableMixinSpec.ts
@@ -2139,4 +2139,14 @@ describe("TableMixin", function () {
expect(item.activeStyle).toBe("parkflag");
});
});
+
+ describe("applies default featureInfoTemplate", function () {
+ it("removes _id_ from template", async function () {
+ item.setTrait(CommonStrata.user, "csvString", LatLonValCsv);
+
+ (await item.loadMapItems()).throwIfError();
+
+ expect(item.featureInfoTemplate.template?.indexOf("_id_")).toBe(-1);
+ });
+ });
});
diff --git a/test/ModelMixins/TileErrorHandlerMixinSpec.ts b/test/ModelMixins/TileErrorHandlerMixinSpec.ts
index 93ecc5525ff..58f3be67c66 100644
--- a/test/ModelMixins/TileErrorHandlerMixinSpec.ts
+++ b/test/ModelMixins/TileErrorHandlerMixinSpec.ts
@@ -62,7 +62,10 @@ describe("TileErrorHandlerMixin", function () {
let item: TestCatalogItem;
let imageryProvider: ImageryProvider;
- const newError = (statusCode: number | undefined, timesRetried = 0) => {
+ const newError = (
+ statusCode: number | undefined,
+ timesRetried = 0
+ ): TileProviderError => {
const httpError = new RequestErrorEvent(statusCode) as any as Error;
return new TileProviderError(
imageryProvider,
@@ -210,9 +213,12 @@ describe("TileErrorHandlerMixin", function () {
it("fails with bad image error if the error defines a target element", async function () {
try {
- const tileProviderError = newError(undefined);
- // @ts-expect-error
- tileProviderError.error = { ...tileProviderError.error, target: {} };
+ const tileProviderError: TileProviderError = newError(undefined);
+
+ tileProviderError.error = {
+ ...tileProviderError.error,
+ target: {}
+ } as Error;
await onTileLoadError(item, tileProviderError);
} catch {
/* eslint-disable-line no-empty */
diff --git a/test/Models/Catalog/CatalogFunctions/YDYRCatalogFunctionSpec.ts b/test/Models/Catalog/CatalogFunctions/YDYRCatalogFunctionSpec.ts
index d36b51abe64..6a346d7f737 100644
--- a/test/Models/Catalog/CatalogFunctions/YDYRCatalogFunctionSpec.ts
+++ b/test/Models/Catalog/CatalogFunctions/YDYRCatalogFunctionSpec.ts
@@ -79,7 +79,7 @@ describe("YDYRCatalogFunction", function () {
csv.setTrait(CommonStrata.user, "csvString", lga11Csv);
await csv.loadRegionProviderList();
await csv.loadMapItems();
- addUserCatalogMember(terria, csv, { enable: true });
+ await addUserCatalogMember(terria, csv, { enable: true });
ydyr = new YDYRCatalogFunction("testYdyr", terria);
ydyr.setTrait(CommonStrata.definition, "parameters", {
@@ -92,7 +92,7 @@ describe("YDYRCatalogFunction", function () {
});
// A few reactions will happen, while setting default values for functionParameters
- await new Promise((resolve, reject) => {
+ await new Promise((resolve) => {
reaction(
() => ydyr.functionParameters,
() => {
diff --git a/test/Models/Catalog/CatalogGroupSpec.ts b/test/Models/Catalog/CatalogGroupSpec.ts
index 08c2db64ece..4c473886baf 100644
--- a/test/Models/Catalog/CatalogGroupSpec.ts
+++ b/test/Models/Catalog/CatalogGroupSpec.ts
@@ -7,7 +7,6 @@ import StubCatalogItem from "../../../lib/Models/Catalog/CatalogItems/StubCatalo
import CatalogMemberFactory from "../../../lib/Models/Catalog/CatalogMemberFactory";
import SplitItemReference from "../../../lib/Models/Catalog/CatalogReferences/SplitItemReference";
import WebMapServiceCatalogItem from "../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
-import { getUniqueStubName } from "../../../lib/Models/Catalog/createStubCatalogItem";
import CommonStrata from "../../../lib/Models/Definition/CommonStrata";
import upsertModelFromJson from "../../../lib/Models/Definition/upsertModelFromJson";
import Terria from "../../../lib/Models/Terria";
@@ -74,7 +73,6 @@ describe("CatalogGroup", function () {
const item = terria.getModelById(CatalogGroup, "mama") as CatalogGroup;
const child1 = terria.getModelById(CatalogGroup, "child1") as CatalogGroup;
- const child2 = terria.getModelById(CatalogGroup, "child2") as CatalogGroup;
expect(item).toBeDefined();
expect(item.type).toBe("group");
expect(item.members).toEqual(["child1", "child2", "child3"]);
@@ -138,7 +136,6 @@ describe("CatalogGroup", function () {
expect(invalidType).toBeDefined();
expect(noType).toBeDefined();
expect(nothingness).toBeDefined();
- const stubName = getUniqueStubName(terria);
if (
member0 !== undefined &&
member1 !== undefined &&
diff --git a/test/Models/Catalog/CatalogGroups/OpenDataSoftCatalogGroupSpec.ts b/test/Models/Catalog/CatalogGroups/OpenDataSoftCatalogGroupSpec.ts
index 93f2fe70f68..5dc0aa03af4 100644
--- a/test/Models/Catalog/CatalogGroups/OpenDataSoftCatalogGroupSpec.ts
+++ b/test/Models/Catalog/CatalogGroups/OpenDataSoftCatalogGroupSpec.ts
@@ -34,7 +34,6 @@ describe("OpenDataSoftCatalogGroup", function () {
});
afterEach(function () {
- console.log(fetchMock.calls());
fetchMock.restore();
});
diff --git a/test/Models/Catalog/CatalogGroups/ThreddsCatalogGroupSpec.ts b/test/Models/Catalog/CatalogGroups/ThreddsCatalogGroupSpec.ts
index 3608c265b61..b7a5aba66d0 100644
--- a/test/Models/Catalog/CatalogGroups/ThreddsCatalogGroupSpec.ts
+++ b/test/Models/Catalog/CatalogGroups/ThreddsCatalogGroupSpec.ts
@@ -1,8 +1,6 @@
import { configure } from "mobx";
import Terria from "../../../../lib/Models/Terria";
-import ThreddsCatalogGroup, {
- ThreddsStratum
-} from "../../../../lib/Models/Catalog/CatalogGroups/ThreddsCatalogGroup";
+import ThreddsCatalogGroup from "../../../../lib/Models/Catalog/CatalogGroups/ThreddsCatalogGroup";
import i18next from "i18next";
import CatalogGroup from "../../../../lib/Models/Catalog/CatalogGroup";
import WebMapServiceCatalogGroup from "../../../../lib/Models/Catalog/Ows/WebMapServiceCatalogGroup";
@@ -15,7 +13,6 @@ configure({
describe("ThreddsCatalogGroup", function () {
let terria: Terria;
let threddsCatalogGroup: ThreddsCatalogGroup;
- let threddsStratum: ThreddsStratum;
beforeEach(async function () {
terria = new Terria({
@@ -26,9 +23,6 @@ describe("ThreddsCatalogGroup", function () {
threddsCatalogGroup.setTrait("definition", "url", url);
await threddsCatalogGroup.loadMembers();
- threddsStratum = threddsCatalogGroup.strata.get(
- ThreddsStratum.stratumName
- ) as ThreddsStratum;
});
it("has a type and typeName", function () {
diff --git a/test/Models/Catalog/CatalogItems/ApiTableCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/ApiTableCatalogItemSpec.ts
index f5c3e130e32..d7c5a1f682e 100644
--- a/test/Models/Catalog/CatalogItems/ApiTableCatalogItemSpec.ts
+++ b/test/Models/Catalog/CatalogItems/ApiTableCatalogItemSpec.ts
@@ -31,8 +31,6 @@ describe("ApiTableCatalogItem", function () {
});
it("creates a table from api calls", async function () {
- const valueApiIdx = 0;
- const positionApiIdx = 1;
runInAction(() => {
updateModelFromJson(apiCatalogItem, CommonStrata.definition, {
idKey: "id",
diff --git a/test/Models/Catalog/CatalogItems/CartoMapV3CatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/CartoMapV3CatalogItemSpec.ts
index aeefd613142..e5ac166db8e 100644
--- a/test/Models/Catalog/CatalogItems/CartoMapV3CatalogItemSpec.ts
+++ b/test/Models/Catalog/CatalogItems/CartoMapV3CatalogItemSpec.ts
@@ -88,7 +88,6 @@ describe("CartoMapV3CatalogItemSpec", function () {
jasmine.Ajax.stubRequest(
"https://BASE_URL/v3/maps/CONNECTION_NAME/query"
).andCallFunction((req) => {
- req.data;
const body = req.data();
// Only respond if correct body parameters
if (
diff --git a/test/Models/Catalog/CatalogItems/Cesium3DTilesCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/Cesium3DTilesCatalogItemSpec.ts
index 3e8bc68ed7c..5e39179b1cb 100644
--- a/test/Models/Catalog/CatalogItems/Cesium3DTilesCatalogItemSpec.ts
+++ b/test/Models/Catalog/CatalogItems/Cesium3DTilesCatalogItemSpec.ts
@@ -316,10 +316,13 @@ describe("Cesium3DTilesCatalogItemSpec", function () {
});
});
- it("correctly builds `Feature` from picked Cesium3DTileFeature", function () {
+ it("correctly builds `Feature` from picked Cesium3DTileFeature", async function () {
const picked = new Cesium3DTileFeature();
spyOn(picked, "getPropertyIds").and.returnValue([]);
- const feature = item.buildFeatureFromPickResult(Cartesian2.ZERO, picked);
+ const feature = await item.buildFeatureFromPickResult(
+ Cartesian2.ZERO,
+ picked
+ );
expect(feature).toBeDefined();
if (feature) {
expect(feature._cesium3DTileFeature).toBe(picked);
@@ -337,7 +340,7 @@ describe("Cesium3DTilesCatalogItemSpec", function () {
"color"
]);
item.setFeatureVisibility(feature, false);
- // @ts-expect-error
+ // @ts-expect-error JsonValue
expect(item.style.show.conditions).toEqual([
['${color} === "red" && ${doorNumber} === 10', false],
["true", true] // fallback rule
diff --git a/test/Models/Catalog/CatalogItems/CogCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/CogCatalogItemSpec.ts
new file mode 100644
index 00000000000..593b45d78b7
--- /dev/null
+++ b/test/Models/Catalog/CatalogItems/CogCatalogItemSpec.ts
@@ -0,0 +1,183 @@
+import { reaction, when } from "mobx";
+import { TIFFImageryProvider } from "terriajs-tiff-imagery-provider";
+import { ImageryParts } from "../../../../lib/ModelMixins/MappableMixin";
+import CogCatalogItem from "../../../../lib/Models/Catalog/CatalogItems/CogCatalogItem";
+import CommonStrata from "../../../../lib/Models/Definition/CommonStrata";
+import updateModelFromJson from "../../../../lib/Models/Definition/updateModelFromJson";
+import Terria from "../../../../lib/Models/Terria";
+
+const TEST_URLS = {
+ "4326": "/test/cogs/4326.tif", // a 1x1 tif in native EPSG:4326 projection
+ "32756": "/test/cogs/32756.tif" // a 1x1 tif in non-native 32756 projection
+};
+
+describe("CogCatalogItem", function () {
+ let item: CogCatalogItem;
+
+ beforeEach(function () {
+ item = new CogCatalogItem("test", new Terria());
+ });
+
+ it("should have a type 'cog'", function () {
+ expect(item.type).toEqual("cog");
+ });
+
+ it("can be instantiated", function () {
+ expect(item).toBeDefined();
+ });
+
+ describe("mapItems", function () {
+ // Test for each valid URL
+ it(`should return a TIFFImageryProvider`, async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ await item.loadMapItems();
+ const mapItem = item.mapItems[0];
+ expect(mapItem).toBeDefined();
+ expect(ImageryParts.is(mapItem)).toBe(true);
+ if (ImageryParts.is(mapItem)) {
+ expect(mapItem.imageryProvider instanceof TIFFImageryProvider).toBe(
+ true
+ );
+ }
+ });
+ });
+
+ describe("TIFFImageryProvider initialization", function () {
+ it("uses the correct url", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+
+ const fromUrl = spyOn(TIFFImageryProvider, "fromUrl").and.callThrough();
+ await item.loadMapItems();
+ expect(item.mapItems[0]).toBeDefined();
+
+ const [url] = fromUrl.calls.first().args;
+ expect(url).toBe(testUrl);
+ });
+
+ it("correctly initializes the basic TIFFImageryProvider options", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ item.setTrait(CommonStrata.user, "credit", "Y");
+ item.setTrait(CommonStrata.user, "tileSize", 1);
+ item.setTrait(CommonStrata.user, "minimumLevel", 5);
+ item.setTrait(CommonStrata.user, "maximumLevel", 10);
+ item.setTrait(CommonStrata.user, "hasAlphaChannel", false);
+ await item.loadMapItems();
+
+ const imageryProvider = getImageryProvider(item);
+ expect(imageryProvider).toBeDefined();
+ expect(imageryProvider.credit.html).toBe("Y");
+ expect(imageryProvider.tileSize).toBe(1);
+ expect(imageryProvider.minimumLevel).toBe(5);
+ expect(imageryProvider.maximumLevel).toBe(10);
+ expect(imageryProvider.hasAlphaChannel).toBe(false);
+ });
+
+ describe("renderOptions", function () {
+ it("is set correctly", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ updateModelFromJson(item.renderOptions, CommonStrata.user, {
+ nodata: 42,
+ convertToRGB: true,
+ resampleMethod: "bilinear"
+ });
+ await item.loadMapItems();
+ const renderOptions = getImageryProvider(item)?.renderOptions;
+ expect(renderOptions).toBeDefined();
+
+ expect(renderOptions.nodata).toBe(42);
+ expect(renderOptions.convertToRGB).toBe(true);
+ expect(renderOptions.resampleMethod).toBe("bilinear");
+ });
+
+ it("uses a default value of `bilinear` for `resampleMethod'", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ updateModelFromJson(item.renderOptions, CommonStrata.user, {});
+ await item.loadMapItems();
+ const renderOptions = getImageryProvider(item)?.renderOptions;
+ expect(renderOptions).toBeDefined();
+ expect(renderOptions.resampleMethod).toBe("nearest");
+ });
+ });
+ });
+
+ describe("reprojection", function () {
+ it("reprojects non native projections", async function () {
+ const testUrl = TEST_URLS["32756"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+
+ const mockReprojector = jasmine.createSpy();
+ item.reprojector = () => mockReprojector;
+ await item.loadMapItems();
+
+ expect(mockReprojector.calls.count()).toBe(1);
+ expect(mockReprojector.calls.first().args[0]).toBe(32756);
+ });
+ });
+
+ describe("imageryProvider destruction", function () {
+ it("destroys the imageryProvider when `mapItems` is no longer observed", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ const destroyReaction = reaction(
+ () => item.mapItems,
+ () => {},
+ { fireImmediately: true }
+ );
+ await when(() => item.mapItems.length > 0);
+ const imageryProvider = getImageryProvider(item);
+ expect(imageryProvider).toBeDefined();
+ const destroy = spyOn(imageryProvider, "destroy");
+
+ destroyReaction();
+ expect(destroy).toHaveBeenCalledTimes(1);
+ });
+
+ it("once destroyed, it re-creates imageryProvider if `mapItems` is observed again", async function () {
+ const testUrl = TEST_URLS["4326"];
+ item.setTrait(CommonStrata.user, "url", testUrl);
+ const destroyReaction1 = reaction(
+ () => item.mapItems,
+ () => {},
+ { fireImmediately: true }
+ );
+ await when(() => item.mapItems.length > 0);
+ const imageryProvider1 = getImageryProvider(item);
+ expect(imageryProvider1).toBeDefined();
+ destroyReaction1();
+ expect(item.mapItems.length).toBe(0);
+
+ const destroyReaction2 = reaction(
+ () => item.mapItems,
+ () => {},
+ { fireImmediately: true }
+ );
+ await when(() => item.mapItems.length > 0);
+ const imageryProvider2 = getImageryProvider(item);
+ expect(imageryProvider2).toBeDefined();
+ destroyReaction2();
+ });
+ });
+});
+
+/**
+ * Utility function to get the imagery provider from a CogCatalogItem.
+ *
+ * @param item The CogCatalogItem to get the imagery provider from.
+ * @returns The TIFFImageryProvider if found, otherwise throws an error.
+ */
+function getImageryProvider(item: CogCatalogItem): TIFFImageryProvider {
+ const mapItem = item.mapItems[0];
+ if (
+ ImageryParts.is(mapItem) &&
+ mapItem.imageryProvider instanceof TIFFImageryProvider
+ ) {
+ return mapItem.imageryProvider;
+ } else {
+ throw new Error("Load failed");
+ }
+}
diff --git a/test/Models/Catalog/CatalogItems/GeoJsonCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/GeoJsonCatalogItemSpec.ts
index c623c3892c3..bf5edb5f51b 100644
--- a/test/Models/Catalog/CatalogItems/GeoJsonCatalogItemSpec.ts
+++ b/test/Models/Catalog/CatalogItems/GeoJsonCatalogItemSpec.ts
@@ -73,12 +73,12 @@ describe("GeoJsonCatalogItemSpec", () => {
type: "Polygon",
coordinates: [
[
- [144.80667114257812, -32.96258644191746],
+ [144.806671142578125, -32.96258644191746],
[145.008544921875, -33.19273094190691],
[145.557861328125, -32.659031913817685],
- [145.04287719726562, -32.375322284319346],
+ [145.042877197265625, -32.375322284319346],
[144.7998046875, -32.96719522935591],
- [144.80667114257812, -32.96258644191746]
+ [144.806671142578125, -32.96258644191746]
]
]
}
@@ -1558,5 +1558,29 @@ describe("GeoJsonCatalogItemSpec", () => {
const terriaFeatureData = features[0].data as TerriaFeatureData;
expect(terriaFeatureData.rowIds).toEqual([4, 5, 6, 7, 8]);
});
+
+ describe("applies default featureInfoTemplate", function () {
+ let terria: Terria;
+ let geojson: GeoJsonCatalogItem;
+
+ beforeEach(async function () {
+ terria = new Terria({
+ baseUrl: "./"
+ });
+ geojson = new GeoJsonCatalogItem("test-geojson", terria);
+ });
+
+ it("removes _id_ from template", async function () {
+ geojson.setTrait(
+ CommonStrata.user,
+ "url",
+ "test/GeoJSON/height.geojson"
+ );
+
+ await geojson.loadMapItems();
+
+ expect(geojson.featureInfoTemplate.template?.indexOf("_id_")).toBe(-1);
+ });
+ });
});
});
diff --git a/test/Models/Catalog/CatalogItems/I3SCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/I3SCatalogItemSpec.ts
new file mode 100644
index 00000000000..f731f5cbb03
--- /dev/null
+++ b/test/Models/Catalog/CatalogItems/I3SCatalogItemSpec.ts
@@ -0,0 +1,173 @@
+import "../../../SpecMain";
+import { reaction, runInAction } from "mobx";
+import i18next from "i18next";
+import Cesium3DTileColorBlendMode from "terriajs-cesium/Source/Scene/Cesium3DTileColorBlendMode";
+import ShadowMode from "terriajs-cesium/Source/Scene/ShadowMode";
+import Terria from "../../../../lib/Models/Terria";
+import I3SCatalogItem from "../../../../lib/Models/Catalog/CatalogItems/I3SCatalogItem";
+import I3SDataProvider from "terriajs-cesium/Source/Scene/I3SDataProvider";
+import Cesium3DTileset from "terriajs-cesium/Source/Scene/Cesium3DTileset";
+import Resource from "terriajs-cesium/Source/Core/Resource";
+import Cesium3DTileFeature from "terriajs-cesium/Source/Scene/Cesium3DTileFeature";
+import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2";
+
+const mockLayerData = {
+ href: "layers/0/",
+ layerType: "3DObject",
+ attributeStorageInfo: [],
+ store: { rootNode: "mockRootNodeUrl", version: "1.6" },
+ fullExtent: { xmin: 0, ymin: 1, xmax: 2, ymax: 3 },
+ spatialReference: { wkid: 4326 },
+ id: 0
+};
+
+const mockProviderData = {
+ name: "mockProviderName",
+ serviceVersion: "1.6",
+ layers: [mockLayerData]
+};
+
+describe("I3SCatalogItemSpec", function () {
+ let item: I3SCatalogItem;
+ const testUrl = "/test/Cesium3DTiles/tileset.json";
+
+ beforeAll(function () {
+ spyOn(Resource.prototype, "fetchJson").and.callFake(function fetch() {
+ return Promise.resolve(mockProviderData);
+ });
+ spyOn(Cesium3DTileset, "fromUrl").and.callFake(async () => {
+ const tileset = new Cesium3DTileset({});
+ /* @ts-expect-error Mock the root tile so that i3s property can be appended */
+ tileset._root = {};
+ return tileset;
+ });
+ });
+
+ beforeEach(function () {
+ item = new I3SCatalogItem("test", new Terria());
+ runInAction(() => {
+ item.setTrait("definition", "url", testUrl);
+ item.setTrait("definition", "allowFeaturePicking", true);
+ });
+ });
+
+ it("should have a type and a typeName", function () {
+ expect(I3SCatalogItem.type).toBe("i3s");
+ expect(item.type).toBe("i3s");
+ expect(item.typeName).toBe(i18next.t("core.dataType.i3s"));
+ });
+
+ it("supports zooming", function () {
+ expect(item.disableZoomTo).toBeFalsy();
+ });
+
+ it("supports show info", function () {
+ expect(item.disableAboutData).toBeFalsy();
+ });
+
+ it("is mappable", function () {
+ expect(item.isMappable).toBeTruthy();
+ });
+
+ describe("after loading", function () {
+ let dispose: () => void;
+ beforeEach(async function () {
+ try {
+ await item.loadMapItems();
+ } catch {
+ /* eslint-disable-line no-empty */
+ }
+ dispose = reaction(
+ () => item.mapItems,
+ () => {}
+ );
+ });
+
+ afterEach(function () {
+ dispose();
+ });
+
+ describe("mapItems", function () {
+ it("has exactly 1 mapItem", function () {
+ expect(item.mapItems.length).toBe(1);
+ });
+
+ describe("the mapItem", function () {
+ it("should be a I3SDataProvider", function () {
+ expect(item.mapItems[0] instanceof I3SDataProvider).toBeTruthy();
+ });
+
+ describe("the tileset", function () {
+ it("sets `show`", function () {
+ runInAction(() => item.setTrait("definition", "show", false));
+ expect(item.mapItems[0].show).toBe(false);
+ });
+
+ it("sets the shadow mode", function () {
+ runInAction(() => item.setTrait("definition", "shadows", "CAST"));
+ const tileset = item.mapItems[0].layers[0].tileset;
+ expect(tileset?.shadows).toBe(ShadowMode.CAST_ONLY);
+ });
+
+ it("sets the color blend mode", function () {
+ runInAction(() => {
+ item.setTrait("definition", "colorBlendMode", "REPLACE");
+ const tileset = item.mapItems[0].layers[0].tileset;
+ expect(tileset?.colorBlendMode).toBe(
+ Cesium3DTileColorBlendMode.REPLACE
+ );
+ });
+ });
+
+ it("sets the color blend amount", function () {
+ runInAction(() => {
+ item.setTrait("user", "colorBlendAmount", 0.42);
+ const tileset = item.mapItems[0].layers[0].tileset;
+ expect(tileset?.colorBlendAmount).toBe(0.42);
+ });
+ });
+
+ it("sets the shadow mode", function () {
+ runInAction(() => item.setTrait("definition", "shadows", "CAST"));
+ const tileset = item.mapItems[0].layers[0].tileset;
+ expect(tileset?.shadows).toBe(ShadowMode.CAST_ONLY);
+ });
+
+ it("sets the style", function () {
+ runInAction(() =>
+ item.setTrait("definition", "style", {
+ show: "${ZipCode} === '19341'"
+ })
+ );
+ const tileset = item.mapItems[0].layers[0].tileset;
+ expect(tileset?.style).toBe(item.cesiumTileStyle);
+ });
+ });
+ });
+ });
+ it("correctly builds `Feature` from picked Cesium3DTileFeature", async function () {
+ const picked = new Cesium3DTileFeature();
+ /* @ts-expect-error - mock i3sNode */
+ picked._content = {
+ tile: {
+ i3sNode: {
+ parent: undefined,
+ loadFields: () => new Promise((f) => f(null)),
+ getFieldsForFeature: () => ({})
+ }
+ }
+ };
+ /* @ts-expect-error - mock featureId */
+ picked._batchId = 0;
+
+ const feature = await item.buildFeatureFromPickResult(
+ Cartesian2.ZERO,
+ picked
+ );
+ expect(feature).toBeDefined();
+ if (feature) {
+ expect(feature._cesium3DTileFeature).toBe(picked);
+ }
+ });
+ });
+});
diff --git a/test/Models/Catalog/CatalogItems/SensorObservationServiceCatalogItemSpec.ts b/test/Models/Catalog/CatalogItems/SensorObservationServiceCatalogItemSpec.ts
index 6e641df2606..3399b6c45f7 100644
--- a/test/Models/Catalog/CatalogItems/SensorObservationServiceCatalogItemSpec.ts
+++ b/test/Models/Catalog/CatalogItems/SensorObservationServiceCatalogItemSpec.ts
@@ -21,7 +21,7 @@ describe("SensorObservationServiceCatalogItem", function () {
beforeEach(function () {
jasmine.Ajax.install();
jasmine.Ajax.addCustomParamParser({
- // @ts-expect-error
+ // @ts-expect-error mock xhr object
test: (xhr) => /^application\/soap\+xml/.test(xhr.contentType()),
parse: (paramString) => paramString
});
diff --git a/test/Models/Catalog/Ckan/CkanCatalogGroupSpec.ts b/test/Models/Catalog/Ckan/CkanCatalogGroupSpec.ts
index a3f22dd32fe..1ece1d358de 100644
--- a/test/Models/Catalog/Ckan/CkanCatalogGroupSpec.ts
+++ b/test/Models/Catalog/Ckan/CkanCatalogGroupSpec.ts
@@ -29,7 +29,6 @@ interface ExtendedLoadWithXhr {
const loadWithXhr: ExtendedLoadWithXhr = _loadWithXhr as any;
describe("CkanCatalogGroup", function () {
- const ckanServerUrl = "http://data.gov.au";
let terria: Terria;
let ckanCatalogGroup: CkanCatalogGroup;
let ckanServerStratum: CkanServerStratum;
diff --git a/test/Models/Catalog/Ckan/CkanItemReferenceSpec.ts b/test/Models/Catalog/Ckan/CkanItemReferenceSpec.ts
index f15fca0d4cd..9b5b45c132d 100644
--- a/test/Models/Catalog/Ckan/CkanItemReferenceSpec.ts
+++ b/test/Models/Catalog/Ckan/CkanItemReferenceSpec.ts
@@ -1,8 +1,6 @@
import i18next from "i18next";
import { runInAction } from "mobx";
-import CkanItemReference, {
- CkanDatasetStratum
-} from "../../../../lib/Models/Catalog/Ckan/CkanItemReference";
+import CkanItemReference from "../../../../lib/Models/Catalog/Ckan/CkanItemReference";
import WebMapServiceCatalogItem from "../../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
import Terria from "../../../../lib/Models/Terria";
import WebMapServiceCatalogGroup from "../../../../lib/Models/Catalog/Ows/WebMapServiceCatalogGroup";
@@ -15,7 +13,6 @@ const wmsNoLayerResource = require("../../../../wwwroot/test/CKAN/wms-no-layer-r
describe("CkanItemReference", function () {
let terria: Terria;
let ckanItemReference: CkanItemReference;
- let ckanDatasetStratum: CkanDatasetStratum;
let ckanItemTarget: any;
beforeEach(async function () {
@@ -75,9 +72,6 @@ describe("CkanItemReference", function () {
);
});
(await ckanItemReference.loadReference()).throwIfError();
- ckanDatasetStratum = ckanItemReference.strata.get(
- CkanDatasetStratum.stratumName
- ) as CkanDatasetStratum;
ckanItemTarget = ckanItemReference.target;
});
@@ -161,9 +155,6 @@ describe("CkanItemReference", function () {
"tax-stats-wms-resource"
);
await ckanItemReference.loadReference();
- ckanDatasetStratum = ckanItemReference.strata.get(
- CkanDatasetStratum.stratumName
- ) as CkanDatasetStratum;
ckanItemTarget = ckanItemReference.target;
expect(ckanItemReference._ckanResource).toBeDefined();
@@ -191,9 +182,6 @@ describe("CkanItemReference", function () {
"wms-no-layers-resource"
);
await ckanItemReference.loadReference();
- ckanDatasetStratum = ckanItemReference.strata.get(
- CkanDatasetStratum.stratumName
- ) as CkanDatasetStratum;
ckanItemTarget = ckanItemReference.target;
expect(ckanItemReference._ckanResource).toBeDefined();
@@ -229,9 +217,6 @@ describe("CkanItemReference", function () {
);
});
await ckanItemReference.loadReference();
- ckanDatasetStratum = ckanItemReference.strata.get(
- CkanDatasetStratum.stratumName
- ) as CkanDatasetStratum;
ckanItemTarget = ckanItemReference.target;
});
it("uses LAYERS from url query string for WMS item", function () {
diff --git a/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts b/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts
index ad896a1f5b9..e748448a353 100644
--- a/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts
+++ b/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts
@@ -460,8 +460,9 @@ describe("WebMapServiceCatalogItem", function () {
});
try {
await wms.loadMetadata();
- //@ts-expect-error
- expect(mapItems[0].imageryProvider.layers).toBe("landsat_barest_earth");
+ expect(
+ (mapItems[0].imageryProvider as WebMapServiceImageryProvider).layers
+ ).toBe("landsat_barest_earth");
} finally {
cleanup();
}
diff --git a/test/Models/Catalog/Ows/WebProcessingServiceCatalogFunctionSpec.ts b/test/Models/Catalog/Ows/WebProcessingServiceCatalogFunctionSpec.ts
index 55c3d9208a4..8cabc518986 100644
--- a/test/Models/Catalog/Ows/WebProcessingServiceCatalogFunctionSpec.ts
+++ b/test/Models/Catalog/Ows/WebProcessingServiceCatalogFunctionSpec.ts
@@ -148,7 +148,7 @@ describe("WebProcessingServiceCatalogFunction", function () {
let dispose: any;
job = (await wps.submitJob()) as WebProcessingServiceCatalogFunctionJob;
- await new Promise((resolve, reject) => {
+ await new Promise((resolve) => {
dispose = reaction(
() => job.downloadedResults,
() => {
@@ -220,7 +220,7 @@ describe("WebProcessingServiceCatalogFunction", function () {
let dispose2: any;
// Wait for job to finish polling, then check if finished
- await new Promise((resolve, reject) => {
+ await new Promise((resolve) => {
dispose2 = reaction(
() => job.refreshEnabled,
() => {
@@ -307,7 +307,7 @@ describe("WebProcessingServiceCatalogFunction", function () {
let dispose2: any;
// Wait for job to finish polling, then check if failed
- await new Promise((resolve, reject) => {
+ await new Promise((resolve) => {
dispose2 = reaction(
() => job.refreshEnabled,
() => {
diff --git a/test/Models/Catalog/allCatalogModelsSpec.ts b/test/Models/Catalog/allCatalogModelsSpec.ts
index c676620df9d..addf1abf5a9 100644
--- a/test/Models/Catalog/allCatalogModelsSpec.ts
+++ b/test/Models/Catalog/allCatalogModelsSpec.ts
@@ -48,7 +48,7 @@ describe("All Catalog models", () => {
// The only correct way to provide a legend is through legendOwnerTraits.
models
.filter(
- ([modelName, model]) => !hasTraits(model, LegendOwnerTraits, "legends")
+ ([_modelName, model]) => !hasTraits(model, LegendOwnerTraits, "legends")
)
.forEach(([modelName, model]) => {
expect((model as any).legends).toBeUndefined(
diff --git a/test/Models/Catalog/esri/ArcGisImageServerCatalogItemSpec.ts b/test/Models/Catalog/esri/ArcGisImageServerCatalogItemSpec.ts
new file mode 100644
index 00000000000..55b7ba2870c
--- /dev/null
+++ b/test/Models/Catalog/esri/ArcGisImageServerCatalogItemSpec.ts
@@ -0,0 +1,780 @@
+import { reaction, runInAction } from "mobx";
+import GeographicTilingScheme from "terriajs-cesium/Source/Core/GeographicTilingScheme";
+import JulianDate from "terriajs-cesium/Source/Core/JulianDate";
+import Rectangle from "terriajs-cesium/Source/Core/Rectangle";
+import WebMercatorTilingScheme from "terriajs-cesium/Source/Core/WebMercatorTilingScheme";
+import loadWithXhr from "../../../../lib/Core/loadWithXhr";
+import ArcGisImageServerImageryProvider from "../../../../lib/Map/ImageryProvider/ArcGisImageServerImageryProvider";
+import ArcGisImageServerCatalogItem from "../../../../lib/Models/Catalog/Esri/ArcGisImageServerCatalogItem";
+import CommonStrata from "../../../../lib/Models/Definition/CommonStrata";
+import createStratumInstance from "../../../../lib/Models/Definition/createStratumInstance";
+import { SelectableDimensionEnum } from "../../../../lib/Models/SelectableDimensions/SelectableDimensions";
+import Terria from "../../../../lib/Models/Terria";
+import { ArcGisImageServerRenderingRule } from "../../../../lib/Traits/TraitsClasses/ArcGisImageServerCatalogItemTraits";
+
+const rasterFnImageServer = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/rasterFns/imageserver.json")
+);
+
+const rasterFnLegend = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/rasterFns/legend.json")
+);
+
+const timeImageServer = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/time/imageserver.json")
+);
+
+const timeLegend = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/time/legend.json")
+);
+
+const timeIdentify = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/time/identify.json")
+);
+
+const tileImageServer = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/tile/imageserver.json")
+);
+
+const tileLegend = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/tile/legend.json")
+);
+
+const tileIdentify = JSON.stringify(
+ require("../../../../wwwroot/test/ArcGisImageServer/tile/identify.json")
+);
+
+let spyOnLoad: any;
+
+describe("ArcGisImageServer", function () {
+ let terria: Terria;
+ let imageServerItem: ArcGisImageServerCatalogItem;
+
+ beforeEach(async function () {
+ spyOnLoad = spyOn(loadWithXhr as any, "load").and.callThrough();
+ jasmine.Ajax.install();
+ jasmine.Ajax.stubRequest(/.*/).andCallFunction((r) => {
+ console.error(r);
+ throw new Error("Unhandled request: " + r.url);
+ });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/rasterfns\/ImageServer\?.+/
+ ).andReturn({ responseText: rasterFnImageServer });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/rasterfns\/ImageServer\/legend\?.+/
+ ).andReturn({ responseText: rasterFnLegend });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/time\/ImageServer\?.+/
+ ).andReturn({ responseText: timeImageServer });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/time\/ImageServer\/legend\?.+/
+ ).andReturn({ responseText: timeLegend });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/tile\/ImageServer\?.+/
+ ).andReturn({ responseText: tileImageServer });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example\.com\/agsimage\/rest\/services\/tile\/ImageServer\/legend\?.+/
+ ).andReturn({ responseText: tileLegend });
+
+ jasmine.Ajax.stubRequest("http://example.com/token").andReturn({
+ responseText: JSON.stringify({
+ token: "fakeToken"
+ })
+ });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example.com\/agsimage\/rest\/services\/.+\/ImageServer\/exportImage\?.+/
+ ).andReturn({
+ responseText: "fakeImage"
+ });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example.com\/agsimage\/rest\/services\/.+\/ImageServer\/tile.+/
+ ).andReturn({
+ responseText: "fakeImage"
+ });
+
+ terria = new Terria();
+ imageServerItem = new ArcGisImageServerCatalogItem(
+ "test",
+ terria,
+ undefined
+ );
+ imageServerItem.setTrait(
+ "definition",
+ "url",
+ "http://example.com/agsimage/rest/services/time/ImageServer"
+ );
+ });
+
+ afterEach(function () {
+ jasmine.Ajax.uninstall();
+ });
+
+ it("has a type", function () {
+ expect(imageServerItem.type).toBe("esri-imageServer");
+ });
+
+ it("supports splitting", function () {
+ expect(imageServerItem.disableSplitter).toBeFalsy();
+ });
+
+ it("supports zooming to extent", function () {
+ expect(imageServerItem.disableZoomTo).toBeFalsy();
+ });
+
+ it("supports preview", function () {
+ expect(imageServerItem.disableAboutData).toBeFalsy();
+ });
+
+ describe("when tokenUrl is set", function () {
+ beforeEach(() => {
+ imageServerItem.setTrait(
+ CommonStrata.definition,
+ "tokenUrl",
+ "http://example.com/token"
+ );
+ });
+
+ it("fetches the token", async function () {
+ await imageServerItem.loadMapItems();
+ expect(spyOnLoad.calls.argsFor(0)[0]).toBe("http://example.com/token");
+ expect(imageServerItem.token).toBe("fakeToken");
+ });
+
+ it("adds the token to subsequent requests", async function () {
+ await imageServerItem.loadMapItems();
+ const tokenre = /token=fakeToken/;
+ expect(tokenre.test(spyOnLoad.calls.argsFor(1)[0])).toBeTruthy();
+ expect(tokenre.test(spyOnLoad.calls.argsFor(2)[0])).toBeTruthy();
+ });
+
+ it("passes the token to the imageryProvider", async function () {
+ await imageServerItem.loadMapItems();
+ const imageryProvider = imageServerItem.mapItems[0]
+ .imageryProvider as ArcGisImageServerImageryProvider;
+
+ expect(imageryProvider.baseResource.queryParameters.token).toBe(
+ "fakeToken"
+ );
+ });
+ });
+
+ describe("basic image server", function () {
+ it("correctly sets `alpha`", function () {
+ runInAction(() =>
+ imageServerItem.setTrait(CommonStrata.definition, "opacity", 0.42)
+ );
+ expect(imageServerItem.mapItems[0].alpha).toBe(0.42);
+ });
+
+ it("correctly sets `show`", function () {
+ runInAction(() =>
+ imageServerItem.setTrait(CommonStrata.definition, "show", false)
+ );
+ expect(imageServerItem.mapItems[0].show).toBe(false);
+ });
+ });
+
+ describe("bandIds", function () {
+ it("adds to parameters", async function () {
+ runInAction(() =>
+ imageServerItem.setTrait(CommonStrata.definition, "bandIds", [2, 3])
+ );
+ expect(imageServerItem.flattenedParameters).toEqual({
+ bandIds: "2,3"
+ });
+
+ await imageServerItem.loadMapItems();
+
+ // Check legend URL
+ expect(spyOnLoad.calls.argsFor(1)[0]).toEqual(
+ "http://example.com/agsimage/rest/services/time/ImageServer/legend?bandIds=2%2C3&f=json"
+ );
+
+ // Check imagery provider
+ const imageryProvider = imageServerItem.mapItems[0]
+ .imageryProvider as ArcGisImageServerImageryProvider;
+
+ expect(imageryProvider.baseResource.queryParameters.bandIds).toEqual(
+ "2,3"
+ );
+ });
+ });
+
+ describe("image server with time", function () {
+ beforeEach(async function () {
+ imageServerItem.setTrait(
+ "definition",
+ "url",
+ "http://example.com/agsimage/rest/services/time/ImageServer"
+ );
+
+ await imageServerItem.loadMetadata();
+ });
+
+ it("sets basic traits", async function () {
+ console.log(imageServerItem);
+ expect(imageServerItem.name).toBe("Some name");
+ expect(imageServerItem.description).toBe("Some description");
+ expect(imageServerItem.rectangle.east).toBe(179.6875);
+ expect(imageServerItem.rectangle.north).toBe(90.25);
+ expect(imageServerItem.rectangle.west).toBe(-180.3125);
+ expect(imageServerItem.rectangle.south).toBe(-90.25);
+ expect(imageServerItem.attribution).toBe("Some copyright");
+ expect(imageServerItem.maximumScale).toBe(0);
+ expect(imageServerItem.maximumLevel).toBeUndefined();
+ expect(imageServerItem.minimumLevel).toBeUndefined();
+ expect(imageServerItem.allowRasterFunction).toBe(true);
+ expect(imageServerItem.availableRasterFunctions.length).toBe(0);
+ expect(imageServerItem.disableRasterFunctionSelectors).toBe(false);
+ expect(imageServerItem.usePreCachedTiles).toBe(false);
+ expect(imageServerItem.tileHeight).toBe(256);
+ expect(imageServerItem.tileWidth).toBe(256);
+ expect(imageServerItem.wkid).toBe(102100);
+ });
+
+ it("creates legend", async function () {
+ expect(imageServerItem.legends.length).toBe(1);
+ expect(imageServerItem.legends[0].items.length).toBe(3);
+ expect(imageServerItem.legends[0].items[0].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAeElEQVQ4ja3RsQ3CQBQE0TlYhAiQ8B04owD334q7gAACJ0jno4n5BTxp/paxXAfS7eunhHqwPADCfJTBm+oRHnbyZCc31SPMJxls+sr2KM1OrnLydvaSLzvk3asGPgvkxeSBQL7cNRAgG14yQH42OMQfApTeuwr+AYLYEoMMYRRCAAAAAElFTkSuQmCC"
+ );
+ expect(imageServerItem.legends[0].items[1].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAh0lEQVQ4jbXTsQ3CQBSD4d/KEx26VCg1M7EBW2UDVkpBdZBQIEikSBR3gSWMB/ga27qU/ospJ50VA0+XB0DcaLzgnb0XHDl4wczRCopSbC1XSZEeLg7oINLoBicjCET7MoNpMYPt6nzKRiy5GkER89XoAfHJZnD33oxcQ6TZ6PGHHapWZ8vwA8yIImKpipDXAAAAAElFTkSuQmCC"
+ );
+ expect(imageServerItem.legends[0].items[2].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAIUlEQVQ4jWP8+/cvAzUBE1VNGzVw1MBRA0cNHDVwCBkIAEMfAx/78kANAAAAAElFTkSuQmCC"
+ );
+
+ expect(imageServerItem.legends[0].items[0].title).toBe(
+ "High : Some Value"
+ );
+ expect(imageServerItem.legends[0].items[1].title).toBe("Some time layer");
+ expect(imageServerItem.legends[0].items[2].title).toBe(
+ "Low : Some Value"
+ );
+ });
+
+ it("creates time intervals", async function () {
+ expect(imageServerItem.startTime).toBe("1981-12-31T00:00:00.000000000Z");
+ expect(imageServerItem.stopTime).toBe("2021-12-30T16:48:00.000000000Z");
+ expect(imageServerItem.currentDiscreteTimeTag).toBe(
+ "2021-12-30T16:48:00Z"
+ );
+ expect(imageServerItem.discreteTimes?.length).toBe(482);
+ });
+
+ it("Sets `time` parameter", async function () {
+ let imageryProvider = imageServerItem.mapItems[0]
+ .imageryProvider as ArcGisImageServerImageryProvider;
+
+ if (!imageServerItem.currentDiscreteJulianDate)
+ throw new Error("No currentDiscreteJulianDate");
+
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ time: JulianDate.toDate(
+ imageServerItem.currentDiscreteJulianDate
+ ).getTime()
+ });
+
+ const time = imageServerItem.discreteTimes?.[100]?.time ?? "";
+
+ runInAction(() => {
+ imageServerItem.setTrait(CommonStrata.definition, "currentTime", time);
+ });
+
+ imageryProvider = imageServerItem.mapItems[0]
+ .imageryProvider as ArcGisImageServerImageryProvider;
+
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ time: new Date(time).getTime()
+ });
+ });
+
+ it("creates next imagery provider", async function () {
+ const time = imageServerItem.discreteTimes?.[100]?.time ?? "";
+ const nextTime = imageServerItem.discreteTimes?.[101]?.time ?? "";
+
+ runInAction(() => {
+ imageServerItem.setTrait(CommonStrata.definition, "currentTime", time);
+ imageServerItem.setTrait(CommonStrata.definition, "isPaused", false);
+ terria.timelineStack.addToTop(imageServerItem);
+ });
+
+ const imageryProvider = imageServerItem.mapItems[0]
+ ?.imageryProvider as ArcGisImageServerImageryProvider;
+ const nextImageryProvider = imageServerItem._nextImageryParts
+ ?.imageryProvider as ArcGisImageServerImageryProvider;
+
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ time: new Date(time).getTime()
+ });
+
+ expect(nextImageryProvider.baseResource.queryParameters).toEqual({
+ time: new Date(nextTime).getTime()
+ });
+ });
+ });
+
+ describe("image server with raster fns", function () {
+ beforeEach(async function () {
+ imageServerItem.setTrait(
+ "definition",
+ "url",
+ "http://example.com/agsimage/rest/services/rasterfns/ImageServer"
+ );
+
+ await imageServerItem.loadMetadata();
+ });
+
+ it("sets basic traits", async function () {
+ expect(imageServerItem.name).toBe("Some name");
+ expect(imageServerItem.description).toBe("Some description");
+ expect(imageServerItem.rectangle.east).toBe(-116.43027039325061);
+ expect(imageServerItem.rectangle.north).toBe(46.31633967431312);
+ expect(imageServerItem.rectangle.west).toBe(-124.63200690054119);
+ expect(imageServerItem.rectangle.south).toBe(41.93340221567374);
+ expect(imageServerItem.attribution).toBe("Some Copyright");
+ expect(imageServerItem.maximumScale).toBe(0);
+ expect(imageServerItem.maximumLevel).toBeUndefined();
+ expect(imageServerItem.minimumLevel).toBeUndefined();
+ expect(imageServerItem.allowRasterFunction).toBe(true);
+ expect(imageServerItem.availableRasterFunctions.length).toBe(3);
+ expect(imageServerItem.disableRasterFunctionSelectors).toBe(false);
+ expect(imageServerItem.usePreCachedTiles).toBe(false);
+ expect(imageServerItem.tileHeight).toBe(256);
+ expect(imageServerItem.tileWidth).toBe(256);
+ expect(imageServerItem.wkid).toBe(102100);
+ });
+
+ it("creates legend", async function () {
+ await imageServerItem.loadMapItems();
+ expect(imageServerItem.legends.length).toBe(1);
+ expect(imageServerItem.legends[0].items.length).toBe(3);
+ expect(imageServerItem.legends[0].items[0].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAT0lEQVQ4je3RwQkAMAgDwAjiz/1XVUTtEE1/zQCHibK7C1JmRjQiWB7MDJqZXJB5obtzQQDQquKCzA0BPKhMB+mV6U/5G96Df8PrSHdTwQOUlT8HeNXIpAAAAABJRU5ErkJggg=="
+ );
+ expect(imageServerItem.legends[0].items[1].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAUElEQVQ4je3UwQkAMQhE0S+kbcGyjSK7RWQOOWQKeMgMaO7+IUpE2MpMlQfA2ntrQfmF3a0FX4fn4P0dVpUWvH/l1+FxDJB97JkxmxmVB8APVtY8xR14rRcAAAAASUVORK5CYII="
+ );
+ expect(imageServerItem.legends[0].items[2].imageUrl).toBe(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAIUlEQVQ4jWP8+/cvAzUBE1VNGzVw1MBRA0cNHDVwCBkIAEMfAx/78kANAAAAAElFTkSuQmCC"
+ );
+
+ expect(imageServerItem.legends[0].items[0].title).toBe(
+ "High : Some value"
+ );
+ expect(imageServerItem.legends[0].items[1].title).toBe("Some label");
+ expect(imageServerItem.legends[0].items[2].title).toBe(
+ "Low : Some value"
+ );
+ });
+
+ it("adds to rasterFn to legend URL - and reloads correctly", async function () {
+ await imageServerItem.loadMapItems();
+
+ expect(spyOnLoad.calls.argsFor(1)[0]).toEqual(
+ "http://example.com/agsimage/rest/services/rasterfns/ImageServer/legend?f=json"
+ );
+
+ // By observing mapItems, we can trigger a reload when the renderingRule changes
+ const disposer = reaction(
+ () => imageServerItem.mapItems,
+ () => {
+ console.log("woo");
+ }
+ );
+
+ runInAction(() => {
+ imageServerItem.setTrait(
+ CommonStrata.user,
+ "renderingRule",
+ createStratumInstance(ArcGisImageServerRenderingRule, {
+ rasterFunction: "RFTAspectColor"
+ })
+ );
+ });
+
+ expect(spyOnLoad.calls.argsFor(4)[0]).toEqual(
+ "http://example.com/agsimage/rest/services/rasterfns/ImageServer/legend?renderingRule={%22rasterFunction%22%3A%22RFTAspectColor%22}&f=json"
+ );
+
+ disposer();
+ });
+
+ it("has raster functions", async function () {
+ expect(imageServerItem.availableRasterFunctions.length).toBe(3);
+ expect(imageServerItem.availableRasterFunctions[0].name).toBe(
+ "RFTAspectColor"
+ );
+ expect(imageServerItem.availableRasterFunctions[1].name).toBe(
+ "RFTHillshade"
+ );
+ expect(imageServerItem.availableRasterFunctions[2].name).toBe(
+ "RFTShadedReliefElevationColorRamp"
+ );
+ expect(imageServerItem.availableRasterFunctions[0].description).toBe(
+ "This function generates a color representation of aspect."
+ );
+ expect(imageServerItem.availableRasterFunctions[1].description).toBe(
+ "This function creates a hillshade effect based on the elevation data source."
+ );
+ expect(imageServerItem.availableRasterFunctions[2].description).toBe(
+ "This function processes the elevation surface as shaded relief. "
+ );
+ });
+
+ it("creates raster fn selectable dimensions", function () {
+ expect(imageServerItem.selectableDimensions.length).toBe(1);
+ let selDim = imageServerItem
+ .selectableDimensions[0] as SelectableDimensionEnum;
+ expect(selDim.name).toBe(
+ "models.arcGisImageServerCatalogItem.rasterFunction"
+ );
+ expect(selDim.allowUndefined).toBeTruthy();
+ expect(selDim.selectedId).toBeUndefined();
+ expect(selDim.options?.length).toBe(3);
+ expect(selDim.options?.[0].id).toBe("RFTAspectColor");
+ expect(selDim.options?.[1].id).toBe("RFTHillshade");
+ expect(selDim.options?.[2].id).toBe("RFTShadedReliefElevationColorRamp");
+
+ runInAction(() => {
+ imageServerItem.setTrait(
+ CommonStrata.user,
+ "renderingRule",
+ createStratumInstance(ArcGisImageServerRenderingRule, {
+ rasterFunction: "RFTHillshade"
+ })
+ );
+ });
+
+ selDim = imageServerItem
+ .selectableDimensions[0] as SelectableDimensionEnum;
+
+ expect(selDim.selectedId).toBe("RFTHillshade");
+ });
+
+ it("adds rasterfn to parameters", function () {
+ runInAction(() => {
+ imageServerItem.setTrait(
+ CommonStrata.user,
+ "renderingRule",
+ createStratumInstance(ArcGisImageServerRenderingRule, {
+ rasterFunction: "RFTHillshade"
+ })
+ );
+ });
+
+ expect(imageServerItem.flattenedParameters).toEqual({
+ renderingRule: '{"rasterFunction":"RFTHillshade"}'
+ });
+ });
+ });
+
+ describe("image server with tiles", function () {
+ beforeEach(async function () {
+ imageServerItem.setTrait(
+ "definition",
+ "url",
+ "http://example.com/agsimage/rest/services/tile/ImageServer"
+ );
+
+ await imageServerItem.loadMetadata();
+ });
+
+ it("sets basic traits", async function () {
+ expect(imageServerItem.name).toBe("Some name");
+ expect(imageServerItem.description).toBe("Some description");
+ expect(imageServerItem.rectangle.east).toBe(-116.43027039325061);
+ expect(imageServerItem.rectangle.north).toBe(46.31633967431312);
+ expect(imageServerItem.rectangle.west).toBe(-124.63200690054119);
+ expect(imageServerItem.rectangle.south).toBe(41.93340221567374);
+ expect(imageServerItem.attribution).toBe("Some copyright");
+ expect(imageServerItem.maximumScale).toBe(1128.497176);
+ expect(imageServerItem.maximumLevel).toBe(19);
+ expect(imageServerItem.minimumLevel).toBe(0);
+ expect(imageServerItem.allowRasterFunction).toBe(true);
+ expect(imageServerItem.availableRasterFunctions.length).toBe(0);
+ expect(imageServerItem.disableRasterFunctionSelectors).toBe(false);
+ expect(imageServerItem.usePreCachedTiles).toBe(true);
+ expect(imageServerItem.tileHeight).toBe(256);
+ expect(imageServerItem.tileWidth).toBe(256);
+ expect(imageServerItem.wkid).toBe(102100);
+ });
+
+ it("disables tile if parameters", async function () {
+ runInAction(() =>
+ imageServerItem.setTrait(CommonStrata.definition, "parameters", {
+ foo: "bar"
+ })
+ );
+ expect(imageServerItem.usePreCachedTiles).toBe(false);
+ });
+
+ it("disables tile if renderRule", async function () {
+ runInAction(() =>
+ imageServerItem.setTrait(
+ CommonStrata.user,
+ "renderingRule",
+ createStratumInstance(ArcGisImageServerRenderingRule, {
+ rasterFunction: "RFTHillshade"
+ })
+ )
+ );
+
+ expect(imageServerItem.usePreCachedTiles).toBe(false);
+ });
+
+ it("creates imagery provider", function () {
+ const imageryProvider = imageServerItem.mapItems[0]
+ ?.imageryProvider as ArcGisImageServerImageryProvider;
+
+ expect(imageryProvider.usePreCachedTiles).toBe(true);
+ });
+ });
+});
+
+describe("ArcGisImageServerImageryProvider", function () {
+ let imageryProvider: ArcGisImageServerImageryProvider;
+
+ beforeEach(function () {
+ spyOnLoad = spyOn(loadWithXhr as any, "load").and.callThrough();
+ jasmine.Ajax.install();
+
+ jasmine.Ajax.stubRequest(/.*/).andCallFunction((r) => {
+ console.error(r);
+ throw new Error("Unhandled request: " + r.url);
+ });
+
+ jasmine.Ajax.stubRequest(
+ /http:\/\/example.com\/agsimage\/rest\/services\/.+\/ImageServer.+/
+ ).andReturn({
+ responseText: "fakeImage"
+ });
+
+ jasmine.Ajax.stubRequest(
+ "http://example.com/agsimage/rest/services/time/ImageServer/identify?f=json&geometryType=esriGeometryPoint&geometry={x%3A%2057.29577951308232%2C%20y%3A%2057.29577951308232%2C%20spatialReference%3A%20{wkid%3A%204326}}&returnCatalogItems=false&token=fakeToken&foo=bar"
+ ).andReturn({
+ responseText: timeIdentify
+ });
+
+ jasmine.Ajax.stubRequest(
+ "http://example.com/agsimage/rest/services/tile/ImageServer/identify?f=json&geometryType=esriGeometryPoint&geometry={x%3A%206378137%2C%20y%3A%207820815.276085484%2C%20spatialReference%3A%20{wkid%3A%203857}}&returnCatalogItems=false&token=fakeToken&foo=bar"
+ ).andReturn({
+ responseText: tileIdentify
+ });
+ });
+
+ afterEach(function () {
+ jasmine.Ajax.uninstall();
+ });
+
+ describe("dynamic web mercator", function () {
+ beforeEach(async function () {
+ imageryProvider = new ArcGisImageServerImageryProvider({
+ url: "http://example.com/agsimage/rest/services/time/ImageServer",
+ token: "fakeToken",
+ credit: "Some credit",
+ parameters: { foo: "bar" },
+ minimumLevel: 1,
+ maximumLevel: 25,
+ rectangle: Rectangle.fromDegrees(-20, -10, 20, 10),
+ enablePickFeatures: true,
+ usePreCachedTiles: false,
+ tileWidth: 256,
+ tileHeight: 256,
+ tilingScheme: new WebMercatorTilingScheme()
+ });
+ });
+
+ it("should be an ArcGisImageServerImageryProvider", function () {
+ expect(
+ imageryProvider instanceof ArcGisImageServerImageryProvider
+ ).toBeTruthy();
+ });
+
+ it("sets basic properties", function () {
+ expect(imageryProvider.credit.html).toBe("Some credit");
+ expect(imageryProvider.minimumLevel).toBe(1);
+ expect(imageryProvider.maximumLevel).toBe(25);
+ expect(imageryProvider.rectangle).toEqual(
+ Rectangle.fromDegrees(-20, -10, 20, 10)
+ );
+ expect(imageryProvider.enablePickFeatures).toBe(true);
+ expect(imageryProvider.tileWidth).toBe(256);
+ expect(imageryProvider.tileHeight).toBe(256);
+ });
+
+ it("sets the URL, token and parameters correctly", function () {
+ expect(imageryProvider.baseResource.toString()).toBe(
+ "http://example.com/agsimage/rest/services/time/ImageServer/?token=fakeToken&foo=bar"
+ );
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ foo: "bar",
+ token: "fakeToken"
+ });
+ });
+
+ it("tilingScheme should be a WebMercatorTilingScheme", function () {
+ expect(
+ imageryProvider.tilingScheme instanceof WebMercatorTilingScheme
+ ).toBeTruthy();
+ });
+
+ it("creates correct image resource", function () {
+ expect(imageryProvider.usePreCachedTiles).toBe(false);
+
+ const testResource = imageryProvider.buildImageResource(0, 0, 2);
+ expect(testResource.url).toBe(
+ "http://example.com/agsimage/rest/services/time/ImageServer/exportImage?bbox=-20037508.342789244%2C10018754.171394622%2C-10018754.171394622%2C20037508.342789244&size=256%2C256&format=png32&transparent=true&f=image&bboxSR=3857&imageSR=3857&token=fakeToken&foo=bar"
+ );
+ });
+ });
+
+ describe("dynamic wgs84", function () {
+ beforeEach(async function () {
+ imageryProvider = new ArcGisImageServerImageryProvider({
+ url: "http://example.com/agsimage/rest/services/time/ImageServer",
+ token: "fakeToken",
+ credit: "Some credit",
+ parameters: { foo: "bar" },
+ minimumLevel: 3,
+ maximumLevel: 5,
+ rectangle: Rectangle.fromDegrees(-20, -10, 20, 10),
+ enablePickFeatures: true,
+ usePreCachedTiles: false,
+ tileWidth: 512,
+ tileHeight: 512,
+ tilingScheme: new GeographicTilingScheme()
+ });
+ });
+
+ it("should be an ArcGisImageServerImageryProvider", function () {
+ expect(
+ imageryProvider instanceof ArcGisImageServerImageryProvider
+ ).toBeTruthy();
+ });
+
+ it("sets basic properties", function () {
+ expect(imageryProvider.credit.html).toBe("Some credit");
+ expect(imageryProvider.minimumLevel).toBe(3);
+ expect(imageryProvider.maximumLevel).toBe(5);
+ expect(imageryProvider.rectangle).toEqual(
+ Rectangle.fromDegrees(-20, -10, 20, 10)
+ );
+ expect(imageryProvider.enablePickFeatures).toBe(true);
+ expect(imageryProvider.tileWidth).toBe(512);
+ expect(imageryProvider.tileHeight).toBe(512);
+ });
+
+ it("sets the URL, token and parameters correctly", function () {
+ expect(imageryProvider.baseResource.toString()).toBe(
+ "http://example.com/agsimage/rest/services/time/ImageServer/?token=fakeToken&foo=bar"
+ );
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ foo: "bar",
+ token: "fakeToken"
+ });
+ });
+
+ it("tilingScheme should be a GeographicTilingScheme", function () {
+ expect(
+ imageryProvider.tilingScheme instanceof GeographicTilingScheme
+ ).toBeTruthy();
+ });
+
+ it("creates correct image resource", function () {
+ expect(imageryProvider.usePreCachedTiles).toBe(false);
+
+ const testResource = imageryProvider.buildImageResource(1, 1, 4);
+ expect(testResource.url).toBe(
+ "http://example.com/agsimage/rest/services/time/ImageServer/exportImage?bbox=-168.75%2C67.5%2C-157.5%2C78.75&size=512%2C512&format=png32&transparent=true&f=image&bboxSR=4326&imageSR=4326&token=fakeToken&foo=bar"
+ );
+ });
+
+ it("picks features", async function () {
+ const features = await imageryProvider.pickFeatures(1, 1, 4, 1, 1);
+
+ expect(features.length).toBe(1);
+ expect(features[0].name).toBe("Pixel");
+ expect(features[0].description).toBe("8");
+ });
+ });
+
+ describe("tiled web mercator", function () {
+ beforeEach(async function () {
+ imageryProvider = new ArcGisImageServerImageryProvider({
+ url: "http://example.com/agsimage/rest/services/tile/ImageServer",
+ token: "fakeToken",
+ credit: "Some credit",
+ parameters: { foo: "bar" },
+ minimumLevel: 0,
+ maximumLevel: 24,
+ rectangle: Rectangle.fromDegrees(-20, -10, 20, 10),
+ enablePickFeatures: true,
+ usePreCachedTiles: true,
+ tileWidth: 256,
+ tileHeight: 256,
+ tilingScheme: new WebMercatorTilingScheme()
+ });
+ });
+
+ it("should be an ArcGisImageServerImageryProvider", function () {
+ expect(
+ imageryProvider instanceof ArcGisImageServerImageryProvider
+ ).toBeTruthy();
+ });
+
+ it("sets basic properties", function () {
+ expect(imageryProvider.credit.html).toBe("Some credit");
+ expect(imageryProvider.minimumLevel).toBe(0);
+ expect(imageryProvider.maximumLevel).toBe(24);
+ expect(imageryProvider.rectangle).toEqual(
+ Rectangle.fromDegrees(-20, -10, 20, 10)
+ );
+ expect(imageryProvider.enablePickFeatures).toBe(true);
+ expect(imageryProvider.tileWidth).toBe(256);
+ expect(imageryProvider.tileHeight).toBe(256);
+ });
+
+ it("sets the URL, token and parameters correctly", function () {
+ expect(imageryProvider.baseResource.toString()).toBe(
+ "http://example.com/agsimage/rest/services/tile/ImageServer/?token=fakeToken&foo=bar"
+ );
+ expect(imageryProvider.baseResource.queryParameters).toEqual({
+ foo: "bar",
+ token: "fakeToken"
+ });
+ });
+
+ it("tilingScheme should be a WebMercatorTilingScheme", function () {
+ expect(
+ imageryProvider.tilingScheme instanceof WebMercatorTilingScheme
+ ).toBeTruthy();
+ });
+
+ it("creates correct image resource", function () {
+ expect(imageryProvider.usePreCachedTiles).toBe(true);
+
+ const testResource = imageryProvider.buildImageResource(1, 1, 4);
+ expect(testResource.url).toBe(
+ "http://example.com/agsimage/rest/services/tile/ImageServer/tile/4/1/1?token=fakeToken&foo=bar"
+ );
+ });
+
+ it("picks features", async function () {
+ const features = await imageryProvider.pickFeatures(1, 1, 4, 1, 1);
+
+ expect(features.length).toBe(1);
+ expect(features[0].name).toBe("Pixel");
+ expect(features[0].description).toBe("178, 135, 99, 255");
+ });
+ });
+});
diff --git a/test/Models/Catalog/esri/ArcGisPortalReferenceItemSpec.ts b/test/Models/Catalog/esri/ArcGisPortalReferenceItemSpec.ts
index 20358256b0a..fe5528b615b 100644
--- a/test/Models/Catalog/esri/ArcGisPortalReferenceItemSpec.ts
+++ b/test/Models/Catalog/esri/ArcGisPortalReferenceItemSpec.ts
@@ -4,9 +4,7 @@ import Terria from "../../../../lib/Models/Terria";
import registerCatalogMembers from "../../../../lib/Models/Catalog/registerCatalogMembers";
import i18next from "i18next";
-import ArcGisPortalItemReference, {
- ArcGisPortalItemStratum
-} from "../../../../lib/Models/Catalog/Esri/ArcGisPortalItemReference";
+import ArcGisPortalItemReference from "../../../../lib/Models/Catalog/Esri/ArcGisPortalItemReference";
import ArcGisFeatureServerCatalogItem from "../../../../lib/Models/Catalog/Esri/ArcGisFeatureServerCatalogItem";
configure({
@@ -24,7 +22,6 @@ const loadWithXhr: ExtendedLoadWithXhr = _loadWithXhr as any;
describe("ArcGisPortalItemReference", function () {
let terria: Terria;
let arcGisPortalItemReference: ArcGisPortalItemReference;
- let arcGisPortalItemStratum: ArcGisPortalItemStratum;
let portalItemTarget: any;
beforeEach(async function () {
@@ -75,10 +72,6 @@ describe("ArcGisPortalItemReference", function () {
});
await arcGisPortalItemReference.loadReference();
- arcGisPortalItemStratum = arcGisPortalItemReference.strata.get(
- ArcGisPortalItemStratum.stratumName
- ) as ArcGisPortalItemStratum;
-
portalItemTarget = arcGisPortalItemReference.target;
});
diff --git a/test/Models/CesiumSpec.ts b/test/Models/CesiumSpec.ts
index 3d67d0b4df5..21b535143a1 100644
--- a/test/Models/CesiumSpec.ts
+++ b/test/Models/CesiumSpec.ts
@@ -254,7 +254,6 @@ describeIfSupported("Cesium Model", function () {
it("should otherwise use the ION terrain specified by configParameters.cesiumTerrainAssetId", async function () {
const fakeIonTerrainProvider = new CesiumTerrainProvider();
- fakeIonTerrainProvider.availability;
const createSpy = spyOn(
cesium as any,
"createTerrainProviderFromIonAssetId"
diff --git a/test/Models/ErrorServiceSpec.ts b/test/Models/ErrorServiceSpec.ts
index eaa5ca9fa7c..9361386623f 100644
--- a/test/Models/ErrorServiceSpec.ts
+++ b/test/Models/ErrorServiceSpec.ts
@@ -1,25 +1,59 @@
-import { initializeErrorServiceProvider } from "../../lib/Models/ErrorServiceProviders/ErrorService";
-import RollbarErrorServiceProvider from "../../lib/Models/ErrorServiceProviders/RollbarErrorServiceProvider";
+import TerriaError from "../../lib/Core/TerriaError";
+import { ErrorServiceProvider } from "../../lib/Models/ErrorServiceProviders/ErrorService";
+import StubErrorServiceProvider from "../../lib/Models/ErrorServiceProviders/StubErrorServiceProvider";
+import Terria from "../../lib/Models/Terria";
-describe("initializeErrorServiceProvider", function () {
- it("can initialize RollbarErrorServiceProvider", async function () {
- const errorService = await initializeErrorServiceProvider({
- provider: "rollbar",
- configuration: {}
+describe("ErrorService", function () {
+ let mockErrorServiceProvider: ErrorServiceProvider;
+ let terria: Terria;
+
+ beforeAll(() => {
+ jasmine.Ajax.stubRequest(/.*/).andError({});
+ jasmine.Ajax.stubRequest(/.*(serverconfig|proxyabledomains).*/).andReturn({
+ responseText: JSON.stringify({ foo: "bar" })
+ });
+ jasmine.Ajax.stubRequest("test-config.json").andReturn({
+ responseText: JSON.stringify({ config: true })
});
- expect(errorService instanceof RollbarErrorServiceProvider).toBe(true);
+ mockErrorServiceProvider = {
+ init: () => {},
+ error: () => {}
+ };
});
- it("throws an error when an invalid provider type is given", async function () {
- let error;
- try {
- await initializeErrorServiceProvider({
- provider: "foo",
- configuration: undefined
- });
- } catch (e: any) {
- error = e;
- }
- expect(error.message).toBe(`Unknown error service provider: foo`);
+ beforeEach(() => {
+ terria = new Terria({
+ appBaseHref: "/",
+ baseUrl: "./"
+ });
+ });
+
+ it("Initializes an error service, passing in config", async function () {
+ const initSpy = spyOn(mockErrorServiceProvider, "init");
+ await terria.start({
+ configUrl: "test-config.json",
+ errorService: mockErrorServiceProvider
+ });
+ expect(initSpy).toHaveBeenCalledTimes(1);
+ });
+
+ it("Gets called with error", async function () {
+ const errorSpy = spyOn(mockErrorServiceProvider, "error").and.callThrough();
+ await terria.start({
+ configUrl: "test-config.json",
+ errorService: mockErrorServiceProvider
+ });
+ const error = new TerriaError({
+ message: "test error"
+ });
+ terria.raiseErrorToUser(error);
+ expect(errorSpy).toHaveBeenCalledWith(error);
+ });
+
+ it("Falls back to stub provider", () => {
+ terria.start({
+ configUrl: "test-config.json"
+ });
+ expect(terria.errorService).toEqual(jasmine.any(StubErrorServiceProvider));
});
});
diff --git a/test/Models/Experiment.ts b/test/Models/Experiment.ts
deleted file mode 100644
index 0a52cab527e..00000000000
--- a/test/Models/Experiment.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { autorun, configure, runInAction } from "mobx";
-import CatalogMemberMixin from "../../lib/ModelMixins/CatalogMemberMixin";
-import MappableMixin from "../../lib/ModelMixins/MappableMixin";
-import CommonStrata from "../../lib/Models/Definition/CommonStrata";
-import Terria from "../../lib/Models/Terria";
-import WebMapServiceCatalogGroup from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogGroup";
-import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
-
-configure({
- enforceActions: "always",
- computedRequiresReaction: true
-});
-
-describe("NewStuff", function () {
- it("test", function () {
- const terria = new Terria();
- const wms = new WebMapServiceCatalogGroup(
- "Taxation Statistics 2011-2012",
- terria
- );
-
- const wmsItem = new WebMapServiceCatalogItem(
- "Taxation Statistics 2011-2012/ckan_95d9e550_8b36_4273_8df7_2b76c140e73a",
- terria
- );
- wmsItem.setTrait(CommonStrata.definition, "name", "Foo");
- terria.addModel(wmsItem);
-
- const wmsItem2 = new WebMapServiceCatalogItem("another", terria);
- wmsItem2.setTrait(CommonStrata.definition, "name", "Another");
- wmsItem2.setTrait(
- CommonStrata.definition,
- "url",
- "https://data.gov.au/geoserver/taxation-statistics-2011-12/wms"
- );
- terria.addModel(wmsItem2);
-
- runInAction(() => {
- wms.setTrait(CommonStrata.definition, "members", [wmsItem2.uniqueId!]);
- wms.setTrait(
- CommonStrata.definition,
- "name",
- "Taxation Statistics 2011-2012"
- );
- wms.setTrait(
- CommonStrata.definition,
- "url",
- "https://data.gov.au/geoserver/taxation-statistics-2011-12/wms"
- );
- });
-
- autorun((dispose) => {
- console.log("Run: " + wms.memberModels.length);
- wms.memberModels.forEach((model) => {
- if (CatalogMemberMixin.isMixedInto(model)) {
- console.log(`${model.name}: ${model.uniqueId}`);
- }
- if (MappableMixin.isMixedInto(model)) {
- console.log(model.mapItems);
- }
- });
- });
-
- expect().nothing();
- });
-});
diff --git a/test/Models/FunctionParameters/DateParameterSpec.ts b/test/Models/FunctionParameters/DateParameterSpec.ts
new file mode 100644
index 00000000000..5a492cbb368
--- /dev/null
+++ b/test/Models/FunctionParameters/DateParameterSpec.ts
@@ -0,0 +1,63 @@
+import Clock from "terriajs-cesium/Source/Core/Clock";
+import JulianDate from "terriajs-cesium/Source/Core/JulianDate";
+import WebProcessingServiceCatalogFunction from "../../../lib/Models/Catalog/Ows/WebProcessingServiceCatalogFunction";
+import CommonStrata from "../../../lib/Models/Definition/CommonStrata";
+import DateParameter from "../../../lib/Models/FunctionParameters/DateParameter";
+import Terria from "../../../lib/Models/Terria";
+
+describe("DateParameter", function () {
+ let catalogFunction: WebProcessingServiceCatalogFunction;
+ let clock: Clock;
+
+ beforeEach(function () {
+ const terria = new Terria();
+ catalogFunction = new WebProcessingServiceCatalogFunction("test", terria);
+ clock = terria.timelineClock;
+ clock.currentTime = JulianDate.fromDate(new Date("2024-01-01T00:00"));
+ });
+
+ describe("its value", function () {
+ it("defaults to undefined", function () {
+ const param = new DateParameter(catalogFunction, {
+ id: "date",
+ clock
+ });
+ expect(param.value).toBeUndefined();
+ });
+
+ describe("when the parameter is marked as required", function () {
+ it("defaults to current clock time", function () {
+ const param = new DateParameter(catalogFunction, {
+ id: "date",
+ clock,
+ isRequired: true
+ });
+ expect(param.value).toBeDefined();
+ expect(param.value).toBe("2024-01-01");
+ });
+ });
+ });
+
+ describe("set value", function () {
+ let param: DateParameter;
+
+ beforeEach(function () {
+ param = new DateParameter(catalogFunction, {
+ id: "date",
+ clock
+ });
+ });
+
+ it("sets the value correctly", function () {
+ param.setValue(CommonStrata.user, "2024-12-01");
+ expect(param.value).toBe("2024-12-01");
+ });
+
+ it("clears the value if the new value is not a valid date time", function () {
+ param.setValue(CommonStrata.user, "2024-12-01");
+ expect(param.value).toBe("2024-12-01");
+ param.setValue(CommonStrata.user, "2024-42-42");
+ expect(param.value).toBeUndefined();
+ });
+ });
+});
diff --git a/test/Models/FunctionParameters/DateTimeParameterSpec.ts b/test/Models/FunctionParameters/DateTimeParameterSpec.ts
new file mode 100644
index 00000000000..42b0f358272
--- /dev/null
+++ b/test/Models/FunctionParameters/DateTimeParameterSpec.ts
@@ -0,0 +1,63 @@
+import Clock from "terriajs-cesium/Source/Core/Clock";
+import JulianDate from "terriajs-cesium/Source/Core/JulianDate";
+import WebProcessingServiceCatalogFunction from "../../../lib/Models/Catalog/Ows/WebProcessingServiceCatalogFunction";
+import CommonStrata from "../../../lib/Models/Definition/CommonStrata";
+import DateTimeParameter from "../../../lib/Models/FunctionParameters/DateTimeParameter";
+import Terria from "../../../lib/Models/Terria";
+
+describe("DateTimeParameter", function () {
+ let catalogFunction: WebProcessingServiceCatalogFunction;
+ let clock: Clock;
+
+ beforeEach(function () {
+ const terria = new Terria();
+ catalogFunction = new WebProcessingServiceCatalogFunction("test", terria);
+ clock = terria.timelineClock;
+ clock.currentTime = JulianDate.fromDate(new Date("2024-01-01T00:00"));
+ });
+
+ describe("its value", function () {
+ it("defaults to undefined", function () {
+ const param = new DateTimeParameter(catalogFunction, {
+ id: "datetime",
+ clock
+ });
+ expect(param.value).toBeUndefined();
+ });
+
+ describe("when the parameter is marked as required", function () {
+ it("defaults to current clock time", function () {
+ const param = new DateTimeParameter(catalogFunction, {
+ id: "datetime",
+ clock,
+ isRequired: true
+ });
+ expect(param.value).toBeDefined();
+ expect(param.value).toBe("2024-01-01T00:00");
+ });
+ });
+ });
+
+ describe("set value", function () {
+ let param: DateTimeParameter;
+
+ beforeEach(function () {
+ param = new DateTimeParameter(catalogFunction, {
+ id: "datetime",
+ clock
+ });
+ });
+
+ it("sets the value correctly", function () {
+ param.setValue(CommonStrata.user, "2024-12-01T00:00");
+ expect(param.value).toBe("2024-12-01T00:00");
+ });
+
+ it("clears the value if the new value is not a valid date time", function () {
+ param.setValue(CommonStrata.user, "2024-12-01T00:00");
+ expect(param.value).toBe("2024-12-01T00:00");
+ param.setValue(CommonStrata.user, "2024-42-42T00:00");
+ expect(param.value).toBeUndefined();
+ });
+ });
+});
diff --git a/test/Models/MapNavigation/MapNavigationModelSpec.ts b/test/Models/MapNavigation/MapNavigationModelSpec.ts
index d322e497c72..1d231f13466 100644
--- a/test/Models/MapNavigation/MapNavigationModelSpec.ts
+++ b/test/Models/MapNavigation/MapNavigationModelSpec.ts
@@ -1,12 +1,10 @@
import Terria from "../../../lib/Models/Terria";
-import ViewState from "../../../lib/ReactViewModels/ViewState";
import MapNavigationModel from "../../../lib/ViewModels/MapNavigation/MapNavigationModel";
import { IMapNavigationItem } from "../../../lib/ViewModels/MapNavigation/MapNavigationModel";
import { GenericMapNavigationItemController } from "../../../lib/ViewModels/MapNavigation/MapNavigationItemController";
describe("MapNavigationModel", function () {
let terria: Terria;
- let viewState: ViewState;
let item1: IMapNavigationItem;
let item2: IMapNavigationItem;
let item3: IMapNavigationItem;
@@ -18,10 +16,6 @@ describe("MapNavigationModel", function () {
terria = new Terria({
baseUrl: "./"
});
- viewState = new ViewState({
- terria: terria,
- catalogSearchProvider: undefined
- });
item1 = {
id: "item1",
name: "item1",
diff --git a/test/Models/SearchProviders/BingMapsSearchProviderSpec.ts b/test/Models/SearchProviders/BingMapsSearchProviderSpec.ts
index 557fe5b848e..a5f9b35d7cb 100644
--- a/test/Models/SearchProviders/BingMapsSearchProviderSpec.ts
+++ b/test/Models/SearchProviders/BingMapsSearchProviderSpec.ts
@@ -52,7 +52,7 @@ describe("BingMapsSearchProvider", function () {
})
);
- const searchResult = bingMapsSearchProvider.search("test");
+ bingMapsSearchProvider.search("test");
expect(test).toHaveBeenCalledWith(
new Resource({
@@ -86,7 +86,7 @@ describe("BingMapsSearchProvider", function () {
false
);
});
- const test = spyOn(loadJsonp, "loadJsonp").and.returnValue(
+ spyOn(loadJsonp, "loadJsonp").and.returnValue(
Promise.resolve({
resourceSets: [
{
diff --git a/test/Models/SearchProviders/CesiumIonSearchProviderSpec.ts b/test/Models/SearchProviders/CesiumIonSearchProviderSpec.ts
index e0858fc3542..49365eca40e 100644
--- a/test/Models/SearchProviders/CesiumIonSearchProviderSpec.ts
+++ b/test/Models/SearchProviders/CesiumIonSearchProviderSpec.ts
@@ -49,7 +49,6 @@ describe("CesiumIonSearchProvider", () => {
new Promise((resolve) => resolve([]))
);
const result = await searchProvider.search("test");
- console.log(result);
expect(result.results.length).toBe(0);
expect(result.message?.content).toBe(
"translate#viewModels.searchNoLocations"
diff --git a/test/Models/TerriaSpec.ts b/test/Models/TerriaSpec.ts
index 9a1eba8fc6b..ea41ef46f2a 100644
--- a/test/Models/TerriaSpec.ts
+++ b/test/Models/TerriaSpec.ts
@@ -1148,7 +1148,7 @@ describe("Terria", function () {
]);
done();
})
- .catch((error) => {
+ .catch((_error) => {
done.fail();
});
});
@@ -1526,11 +1526,13 @@ describe("Terria", function () {
describe("mapSettings", function () {
it("properly interprets map hash parameter", async () => {
const getLocalPropertySpy = spyOn(terria, "getLocalProperty");
- //@ts-expect-error
- const location: Location = {
+ const location = {
href: "http://test.com/#map=2d"
- };
- await terria.start({ configUrl: "", applicationUrl: location });
+ } as Location;
+ await terria.start({
+ configUrl: "",
+ applicationUrl: location
+ });
await terria.loadPersistedMapSettings();
expect(terria.mainViewer.viewerMode).toBe(ViewerMode.Leaflet);
expect(getLocalPropertySpy).not.toHaveBeenCalledWith("viewermode");
@@ -1552,11 +1554,13 @@ describe("Terria", function () {
terria,
"getLocalProperty"
).and.returnValue("3dsmooth");
- //@ts-expect-error
- const location: Location = {
+ const location = {
href: "http://test.com/#map=4d"
- };
- await terria.start({ configUrl: "", applicationUrl: location });
+ } as Location;
+ await terria.start({
+ configUrl: "",
+ applicationUrl: location
+ });
await terria.loadPersistedMapSettings();
expect(terria.mainViewer.viewerMode).toBe(ViewerMode.Cesium);
expect(terria.mainViewer.viewerOptions.useTerrain).toBe(false);
@@ -1584,7 +1588,7 @@ describe("Terria", function () {
await terria.loadInitSources();
expect(terria.baseMaximumScreenSpaceError).toBe(1);
- expect(terria.useNativeResolution).toBeTruthy;
+ expect(terria.useNativeResolution).toBeTruthy();
expect(terria.timelineStack.alwaysShowingTimeline).toBeTruthy();
expect(setBaseMapSpy).toHaveBeenCalledWith(
terria.baseMapsModel.baseMapItems.find(
diff --git a/test/Models/WorkbenchSpec.ts b/test/Models/WorkbenchSpec.ts
index 70553b9dd08..0fa10c69b77 100644
--- a/test/Models/WorkbenchSpec.ts
+++ b/test/Models/WorkbenchSpec.ts
@@ -1,16 +1,20 @@
import CommonStrata from "../../lib/Models/Definition/CommonStrata";
import MagdaReference from "../../lib/Models/Catalog/CatalogReferences/MagdaReference";
-import { BaseModel } from "../../lib/Models/Definition/Model";
import Terria from "../../lib/Models/Terria";
import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
import Workbench from "../../lib/Models/Workbench";
import Result from "../../lib/Core/Result";
import TerriaError, { TerriaErrorSeverity } from "../../lib/Core/TerriaError";
+import TerriaReference from "../../lib/Models/Catalog/CatalogReferences/TerriaReference";
describe("Workbench", function () {
let terria: Terria;
let workbench: Workbench;
- let item1: BaseModel, item2: BaseModel, item3: BaseModel, item4: BaseModel;
+ let item1: WebMapServiceCatalogItem,
+ item2: WebMapServiceCatalogItem,
+ item3: WebMapServiceCatalogItem,
+ item4: WebMapServiceCatalogItem,
+ ref: TerriaReference;
beforeEach(function () {
terria = new Terria();
@@ -20,6 +24,9 @@ describe("Workbench", function () {
item2 = new WebMapServiceCatalogItem("B", terria);
item3 = new WebMapServiceCatalogItem("C", terria);
item4 = new WebMapServiceCatalogItem("D", terria);
+ ref = new TerriaReference("test", new Terria());
+ ref.setTrait(CommonStrata.user, "url", "test/init/wms-v8.json");
+ ref.setTrait(CommonStrata.user, "path", ["MLzS8W", "fCUx4Y"]);
item1.setTrait("definition", "url", "test/WMS/single_metadata_url.xml");
item2.setTrait("definition", "url", "test/WMS/single_metadata_url.xml");
@@ -31,6 +38,24 @@ describe("Workbench", function () {
terria.addModel(item3);
});
+ it("can collapse/expand all catalog items", async function () {
+ // See if it is compatible with references as well as ordinary catalog items.
+ workbench.items = [item1, ref];
+ await ref.loadReference();
+ workbench.collapseAll();
+ expect(item1.isOpenInWorkbench).toBe(false);
+ expect((ref.target as WebMapServiceCatalogItem).isOpenInWorkbench).toBe(
+ false
+ );
+ expect(workbench.shouldExpandAll).toBe(true);
+ workbench.expandAll();
+ expect(item1.isOpenInWorkbench).toBe(true);
+ expect((ref.target as WebMapServiceCatalogItem).isOpenInWorkbench).toBe(
+ true
+ );
+ expect(workbench.shouldExpandAll).toBe(false);
+ });
+
it("re-orders items correctly", function () {
workbench.items = [item1, item2, item3];
diff --git a/test/Models/parseCustomMarkdownToReactTsSpec.ts b/test/Models/parseCustomMarkdownToReactTsSpec.ts
index 10b4c7128b2..55a2693ce76 100644
--- a/test/Models/parseCustomMarkdownToReactTsSpec.ts
+++ b/test/Models/parseCustomMarkdownToReactTsSpec.ts
@@ -1,6 +1,5 @@
import { parseCustomMarkdownToReactWithOptions } from "../../lib/ReactViews/Custom/parseCustomMarkdownToReact";
import registerCustomComponentTypes from "../../lib/ReactViews/Custom/registerCustomComponentTypes";
-import Terria from "../../lib/Models/Terria";
import { TooltipWithButtonLauncher } from "../../lib/ReactViews/Generic/TooltipWrapper";
const isComponentOfType: any =
@@ -8,12 +7,7 @@ const isComponentOfType: any =
const findAll: any = require("react-shallow-testutils").findAll;
describe("parseCustomMarkdownToReactTs", function () {
- let terria: Terria;
-
beforeEach(function () {
- terria = new Terria({
- baseUrl: "./"
- });
registerCustomComponentTypes();
});
it("correctly parses tooltip terms", function () {
diff --git a/test/ReactViews/Custom/Chart/BottomDockChartSpec.tsx b/test/ReactViews/Custom/Chart/BottomDockChartSpec.tsx
index 3851c078098..f2e71fe67fd 100644
--- a/test/ReactViews/Custom/Chart/BottomDockChartSpec.tsx
+++ b/test/ReactViews/Custom/Chart/BottomDockChartSpec.tsx
@@ -1,6 +1,8 @@
-import { ReactTestRenderer } from "react-test-renderer";
+import TestRenderer, { act, ReactTestRenderer } from "react-test-renderer";
import { ChartItem } from "../../../../lib/ModelMixins/ChartableMixin";
import Terria from "../../../../lib/Models/Terria";
+import BottomDockChart from "../../../../lib/ReactViews/Custom/Chart/BottomDockChart";
+import PointOnMap from "../../../../lib/ReactViews/Custom/Chart/PointOnMap";
describe("BottomDockChart", function () {
let terria: Terria;
@@ -49,21 +51,19 @@ describe("BottomDockChart", function () {
];
});
- // FIXME: disabling because the new version of `withParentSize` from
- // `@vx/responsive` uses ResizeObserver to trigger render which doesn't seem to
- // work correctly in tests
- //
- /* it("renders all points on map for active chart items", function() {
- * act(() => {
- * testRenderer = TestRenderer.create(
- *
- * );
- * });
- * const pointsOnMap = testRenderer.root.findAllByType(PointOnMap);
- * expect(pointsOnMap.length).toBe(2);
- * }); */
+ it("renders all points on map for active chart items", function () {
+ act(() => {
+ testRenderer = TestRenderer.create(
+
+ );
+ });
+ const pointsOnMap = testRenderer.root.findAllByType(PointOnMap);
+ expect(pointsOnMap.length).toBe(2);
+ });
});
diff --git a/test/ReactViews/Custom/Chart/ChartCustomComponentSpec.tsx b/test/ReactViews/Custom/Chart/ChartCustomComponentSpec.tsx
index 1eb3a58f81b..4f42bf8e580 100644
--- a/test/ReactViews/Custom/Chart/ChartCustomComponentSpec.tsx
+++ b/test/ReactViews/Custom/Chart/ChartCustomComponentSpec.tsx
@@ -81,10 +81,7 @@ describe("ChartCustomComponent", function () {
sources: "a, b"
}
};
- const spy = spyOn(
- component,
- "constructShareableCatalogItem"
- ).and.callThrough();
+ spyOn(component, "constructShareableCatalogItem").and.callThrough();
component.processNode(context, node, [], 0);
expect(component.constructShareableCatalogItem).toHaveBeenCalledTimes(2);
// Make sure the id is dependent on parent, title & source name
diff --git a/test/ReactViews/DimensionSelectorSectionSpec.tsx b/test/ReactViews/DimensionSelectorSectionSpec.tsx
index 6a73decb1cf..e0469918cf7 100644
--- a/test/ReactViews/DimensionSelectorSectionSpec.tsx
+++ b/test/ReactViews/DimensionSelectorSectionSpec.tsx
@@ -43,7 +43,7 @@ export default class TestCatalogItem
],
selectedId: "option-2",
allowUndefined: true,
- setDimensionValue: (stratumId: string, newStyle: string) => {}
+ setDimensionValue: (_stratumId: string, _newStyle: string) => {}
},
{
id: "some-id-2",
@@ -55,7 +55,7 @@ export default class TestCatalogItem
],
selectedId: "option-3",
allowUndefined: false,
- setDimensionValue: (stratumId: string, newStyle: string) => {}
+ setDimensionValue: (_stratumId: string, _newStyle: string) => {}
},
{
id: "some-id-3",
@@ -67,7 +67,7 @@ export default class TestCatalogItem
],
selectedId: "option-8",
allowUndefined: false,
- setDimensionValue: (stratumId: string, newStyle: string) => {},
+ setDimensionValue: (_stratumId: string, _newStyle: string) => {},
disable: true
},
{
@@ -79,7 +79,7 @@ export default class TestCatalogItem
],
selectedId: "false",
type: "checkbox",
- setDimensionValue: (stratumId, newStyle) => {}
+ setDimensionValue: (_stratumId, _newStyle) => {}
}
];
}
diff --git a/test/ReactViews/FeatureInfoSectionSpec.tsx b/test/ReactViews/FeatureInfoSectionSpec.tsx
index ebfbc6bc47f..6b023426295 100644
--- a/test/ReactViews/FeatureInfoSectionSpec.tsx
+++ b/test/ReactViews/FeatureInfoSectionSpec.tsx
@@ -25,10 +25,10 @@ import TerriaFeature from "../../lib/Models/Feature/Feature";
import Terria from "../../lib/Models/Terria";
import ViewState from "../../lib/ReactViewModels/ViewState";
import { FeatureInfoSection } from "../../lib/ReactViews/FeatureInfo/FeatureInfoSection";
-import mixTraits from "../../lib/Traits/mixTraits";
import DiscretelyTimeVaryingTraits from "../../lib/Traits/TraitsClasses/DiscretelyTimeVaryingTraits";
import FeatureInfoUrlTemplateTraits from "../../lib/Traits/TraitsClasses/FeatureInfoTraits";
import MappableTraits from "../../lib/Traits/TraitsClasses/MappableTraits";
+import mixTraits from "../../lib/Traits/mixTraits";
import * as FeatureInfoPanel from "../../lib/ViewModels/FeatureInfoPanel";
import { createWithContexts } from "./withContext";
import CsvCatalogItem from "../../lib/Models/Catalog/CatalogItems/CsvCatalogItem";
@@ -382,6 +382,31 @@ describe("FeatureInfoSection", function () {
expect(findWithText(result, "ham").length).toEqual(1);
});
+ it("gracefully handles bad nested JSON", function () {
+ feature = new Entity({
+ name: "Meals",
+ properties: {
+ somethingBad: "{broken object",
+ somethingGood: JSON.stringify({ good: "this object is good" })
+ }
+ });
+ const section = (
+ {}}
+ />
+ );
+ const result = createWithContexts(viewState, section);
+
+ expect(findWithText(result, "{broken object").length).toEqual(1);
+ expect(
+ findWithText(result, `{"good":"this object is good"}`).length
+ ).toEqual(1);
+ });
+
describe("templating", function () {
it("uses and completes a string-form featureInfoTemplate if present", function () {
const template = "This is a {{material}} {{foo}}.";
diff --git a/test/ReactViews/Map/Panels/LangPanel/LangPanelSpec.tsx b/test/ReactViews/Map/Panels/LangPanel/LangPanelSpec.tsx
index 2003f843a51..e1b298084cf 100644
--- a/test/ReactViews/Map/Panels/LangPanel/LangPanelSpec.tsx
+++ b/test/ReactViews/Map/Panels/LangPanel/LangPanelSpec.tsx
@@ -3,13 +3,11 @@ import React from "react";
import { act } from "react-dom/test-utils";
import Terria from "../../../../../lib/Models/Terria";
-import ViewState from "../../../../../lib/ReactViewModels/ViewState";
import LangPanel from "../../../../../lib/ReactViews/Map/Panels/LangPanel/LangPanel";
describe("LangPanel", function () {
let terria: Terria;
- let viewState: ViewState;
let testRenderer: any;
@@ -17,11 +15,6 @@ describe("LangPanel", function () {
terria = new Terria({
baseUrl: "./"
});
-
- viewState = new ViewState({
- terria: terria,
- catalogSearchProvider: undefined
- });
});
it("should not render if there is no langauge config", function () {
diff --git a/test/ReactViews/Mobile/MobileHeaderSpec.tsx b/test/ReactViews/Mobile/MobileHeaderSpec.tsx
index 12f94b252ba..c6a22699681 100644
--- a/test/ReactViews/Mobile/MobileHeaderSpec.tsx
+++ b/test/ReactViews/Mobile/MobileHeaderSpec.tsx
@@ -17,7 +17,6 @@ describe("MobileHeader", function () {
terria = new Terria({
baseUrl: "./"
});
- terria;
viewState = new ViewState({
terria: terria,
catalogSearchProvider: undefined
diff --git a/test/ReactViews/MoreShallowTools.js b/test/ReactViews/MoreShallowTools.js
index c52e091d7da..a8b249bf490 100644
--- a/test/ReactViews/MoreShallowTools.js
+++ b/test/ReactViews/MoreShallowTools.js
@@ -16,7 +16,7 @@ export function getShallowRenderedOutput(jsx) {
export function getMountedInstance(jsx) {
const renderer = getRenderedRenderer(jsx);
- return renderer.getMountedInstance(renderer);
+ return renderer.getMountedInstance();
}
export function findAllEqualTo(reactElement, text) {
diff --git a/test/ReactViews/Tools/ItemSearchTool/SearchFormSpec.tsx b/test/ReactViews/Tools/ItemSearchTool/SearchFormSpec.tsx
index ff4fdaa7ed1..d2c928bb864 100644
--- a/test/ReactViews/Tools/ItemSearchTool/SearchFormSpec.tsx
+++ b/test/ReactViews/Tools/ItemSearchTool/SearchFormSpec.tsx
@@ -63,6 +63,6 @@ function render(
act(() => {
rendered = create( );
});
- // @ts-expect-error
+ // @ts-expect-error assigned in callback
return rendered;
}
diff --git a/test/ReactViews/Tools/ItemSearchTool/SearchResultsSpec.tsx b/test/ReactViews/Tools/ItemSearchTool/SearchResultsSpec.tsx
index 734da60a44a..6e98364b89e 100644
--- a/test/ReactViews/Tools/ItemSearchTool/SearchResultsSpec.tsx
+++ b/test/ReactViews/Tools/ItemSearchTool/SearchResultsSpec.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import { act, create, ReactTestRenderer } from "react-test-renderer";
import { ItemSearchResult } from "../../../../lib/Models/ItemSearchProviders/ItemSearchProvider";
import Terria from "../../../../lib/Models/Terria";
@@ -30,7 +29,7 @@ async function render(
act(() => {
rendered = create( );
});
- // @ts-expect-error
+ // @ts-expect-error assigned in callback
return rendered;
}
diff --git a/test/ReactViews/Workbench/Controls/FilterSectionSpec.tsx b/test/ReactViews/Workbench/Controls/FilterSectionSpec.tsx
new file mode 100644
index 00000000000..666ceb0cf45
--- /dev/null
+++ b/test/ReactViews/Workbench/Controls/FilterSectionSpec.tsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { act } from "react-dom/test-utils";
+import TestRenderer, { ReactTestRenderer } from "react-test-renderer";
+import FilterSection from "../../../../lib/ReactViews/Workbench/Controls/FilterSection";
+import { Range } from "rc-slider";
+import Terria from "../../../../lib/Models/Terria";
+import CommonStrata from "../../../../lib/Models/Definition/CommonStrata";
+import CreateModel from "../../../../lib/Models/Definition/CreateModel";
+import { FilterTraits } from "../../../../lib/Traits/TraitsClasses/Cesium3dTilesTraits";
+import objectArrayTrait from "../../../../lib/Traits/Decorators/objectArrayTrait";
+import ModelTraits from "../../../../lib/Traits/ModelTraits";
+import { runInAction } from "mobx";
+
+class TestTraits extends ModelTraits {
+ @objectArrayTrait({
+ type: FilterTraits,
+ idProperty: "name",
+ name: "filters",
+ description: "The filters to apply to this catalog item."
+ })
+ filters?: FilterTraits[];
+}
+
+class TestModel extends CreateModel(TestTraits) {}
+
+describe("FilterSectionSpec", function () {
+ let testRenderer: ReactTestRenderer;
+ let terria: Terria;
+ let item: TestModel;
+
+ beforeAll(() => {
+ terria = new Terria({
+ baseUrl: "./"
+ });
+ item = new TestModel("test", terria);
+ });
+
+ it("Renders nothing if no filters", function () {
+ testRenderer = TestRenderer.create( );
+ expect(testRenderer.root.children.length).toBe(0);
+ });
+
+ it("Renders a range input for each filter", function () {
+ runInAction(() => {
+ const filter = item.addObject(
+ CommonStrata.user,
+ "filters",
+ "level-filter"
+ );
+ filter?.setTrait(CommonStrata.user, "property", "level");
+ filter?.setTrait(CommonStrata.user, "minimumValue", 0);
+ filter?.setTrait(CommonStrata.user, "maximumValue", 42);
+ filter?.setTrait(CommonStrata.user, "minimumShown", 10);
+ filter?.setTrait(CommonStrata.user, "maximumShown", 20);
+ });
+
+ act(() => {
+ testRenderer = TestRenderer.create( );
+ const rangeInputs = testRenderer.root.findAllByType(Range);
+ expect(rangeInputs.length).toBe(1);
+ });
+ });
+});
diff --git a/test/ReactViews/Workbench/Controls/LegendSpec.tsx b/test/ReactViews/Workbench/Controls/LegendSpec.tsx
index b3f5b6e7ce0..06bdc4ad71e 100644
--- a/test/ReactViews/Workbench/Controls/LegendSpec.tsx
+++ b/test/ReactViews/Workbench/Controls/LegendSpec.tsx
@@ -1,6 +1,5 @@
const findAllWithClass = require("react-shallow-testutils").findAllWithClass;
-import React from "react";
import TestRenderer from "react-test-renderer";
import CsvCatalogItem from "../../../../lib/Models/Catalog/CatalogItems/CsvCatalogItem";
import WebMapServiceCatalogItem from "../../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
@@ -49,8 +48,7 @@ describe("Legend", function () {
.then(() => {
const legendSection = ;
const result = getShallowRenderedOutput(legendSection);
- // @ts-expect-error
- expect(result).toEqual(null);
+ expect(result).toBeNull();
})
.then(done);
});
diff --git a/test/ViewModels/UploadDataTypesSpec.ts b/test/ViewModels/UploadDataTypesSpec.ts
index f419c58e2b1..b0c2aeb7460 100644
--- a/test/ViewModels/UploadDataTypesSpec.ts
+++ b/test/ViewModels/UploadDataTypesSpec.ts
@@ -16,7 +16,7 @@ describe("UploadDataTypes", function () {
});
it("returns all the builtin remote upload types", function () {
- expect(UploadDataTypes.getDataTypes().remoteDataType.length).toEqual(23);
+ expect(UploadDataTypes.getDataTypes().remoteDataType.length).toEqual(26);
});
});
@@ -56,7 +56,8 @@ describe("UploadDataTypes", function () {
{
value: "foo42",
name: "Another Foo type",
- description: "Some other foo files"
+ description: "Some other foo files",
+ customComponent: undefined
}
]);
});
@@ -82,12 +83,14 @@ describe("UploadDataTypes", function () {
{
value: "foo42",
name: "Foo type",
- description: "Foo files"
+ description: "Foo files",
+ customComponent: undefined
},
{
value: "foo42",
name: "Another Foo type",
- description: "Some other foo files"
+ description: "Some other foo files",
+ customComponent: undefined
}
]);
});
@@ -129,7 +132,8 @@ describe("UploadDataTypes", function () {
{
value: "foo42",
name: "Another Foo type",
- description: "Some other foo files"
+ description: "Some other foo files",
+ customComponent: undefined
}
]);
});
@@ -155,12 +159,14 @@ describe("UploadDataTypes", function () {
{
value: "foo42",
name: "Foo type",
- description: "Foo files"
+ description: "Foo files",
+ customComponent: undefined
},
{
value: "foo42",
name: "Another Foo type",
- description: "Some other foo files"
+ description: "Some other foo files",
+ customComponent: undefined
}
]);
});
diff --git a/wwwroot/cesium-ion-oauth2.html b/wwwroot/cesium-ion-oauth2.html
new file mode 100644
index 00000000000..ea8ae6ac4e2
--- /dev/null
+++ b/wwwroot/cesium-ion-oauth2.html
@@ -0,0 +1,36 @@
+
+
+
+ Cesium ion OAuth2 Token Exchange
+
+
+
+
diff --git a/wwwroot/languages/ca/translation.json b/wwwroot/languages/ca/translation.json
index d1b175bde64..72c2d6b6f77 100644
--- a/wwwroot/languages/ca/translation.json
+++ b/wwwroot/languages/ca/translation.json
@@ -709,7 +709,10 @@
"assimp-local-description": "**Avís:** el convertidor de fitxers 3D és experimental.\nConsulteu la llista de [formats admesos](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md).\nEls fitxers s'han de comprimir.",
"assimp-remote": "Convertidor de fitxers 3D (experimental)",
"assimp-remote-description": "**Avís:** el convertidor de fitxers 3D és experimental.\nConsulteu la llista de [formats admesos](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md).\nTambé s'admeten fitxers zip",
- "carto-v3": "Carto V3"
+ "carto-v3": "Carto V3",
+ "i3s": "I3S",
+ "esri-imageServer": "Esri ArcGIS ImageServer (capa única)",
+ "cesium-ion": "Cesium ion"
},
"printWindow": {
"errorTitle": "Error d'impressió",
@@ -2079,6 +2082,14 @@
"name": "Mín"
},
"name": "Estil"
+ },
+ "arcGisImageServerCatalogItem": {
+ "invalidUrlTitle": "No es pot carregar ImageServer",
+ "invalidServiceTitle": "ArcGIS Image Service invàlid",
+ "rasterFunction": "Funció de ràster",
+ "name": "Esri ArcGIS ImageServer",
+ "invalidUrlMessage": "No s'ha pogut carregar el punt final de l'ArcGis ImageServer perquè l'element del catàleg no té una \"url\".",
+ "invalidServiceMessage": "S'ha produït un error en invocar ArcGIS Image Service. La resposta del servidor no sembla ser un document Image Service vàlid."
}
},
"deltaTool": {
diff --git a/wwwroot/languages/cs/translation.json b/wwwroot/languages/cs/translation.json
index 563bd1949d5..360b220364b 100644
--- a/wwwroot/languages/cs/translation.json
+++ b/wwwroot/languages/cs/translation.json
@@ -197,7 +197,7 @@
},
"share": {
"browserPrint": "Chcete-li dosáhnout lepších výsledků při tisku, použijte místo funkce tisku webového prohlížeče tlačítko Tisk {{appName}}.",
- "localDataNote": "<0><0>Poznámka:0>0><1>Následující zdroje dat NEBUDOU sdíleny, protože obsahují data z tohoto místního systému. Chcete-li tyto zdroje dat sdílet, zveřejněte jejich data na webovém serveru a <2>přidejte je pomocí url adresy2>.1>",
+ "localDataNote": "<0><0>Poznámka:0>0><1>Následující zdroje dat NEBUDOU sdíleny, protože obsahují data z tohoto místního systému nebo z ověřené online služby. Chcete-li tyto zdroje dat sdílet, zveřejněte jejich data na webovém serveru a <2>přidejte je pomocí url adresy2>.1>",
"generatingUrl": "Generování sdílené adresy URL...",
"printTitle": "Tisk mapy",
"printExplanation": "Otevřít tisknutelnou verzi této mapy.",
@@ -463,7 +463,7 @@
"resultsLabel": "Výsledky hledání",
"done": "Hotovo",
"data": "Data",
- "searchInDataCatalog": "Hledání <1>'{{locationSearchText}}'1> v katalogu dat",
+ "searchInDataCatalog": "Hledání '{{locationSearchText}}' v katalogu dat",
"search": "Hledat '{{searchText}}' v Katalogu dat",
"viewMore": "Zobrazit více výsledků {{name}}",
"placeholder": "Hledání lokalit",
@@ -504,7 +504,8 @@
"previewItemErrorTitle": "Položku katalogu nelze zobrazit.",
"dataDescription": "Popis dat",
"resourceDescription": "Popis Zdroje",
- "mayBeExperiencingIssues": "U této datové sady může v současné době docházet k problémům"
+ "mayBeExperiencingIssues": "U této datové sady může v současné době docházet k problémům",
+ "selectMultipleDatasets": "<0>Stiskněte Shift a klikněte0><1 /><2>pro přidání více datových sad2>"
},
"description": {
"name": "Popis",
@@ -649,7 +650,7 @@
"expand": "Rozbalit",
"download": "Stáhnout",
"loading": "Načítání dat grafu...",
- "noData": "Nenalezeny žádné údaje, které by bylo možné zobrazit v tabulce.",
+ "noData": "Nebyla nalezena žádná data grafu.",
"showItemInChart": "Zobrazit {{value}} v tabulce"
},
"viewModels": {
@@ -662,7 +663,10 @@
"searchLocations": "Poloha",
"searchNoPlaceNames": "Litujeme, ale vašemu vyhledávacímu dotazu neodpovídají žádné oficiální názvy míst.",
"searchErrorOccurred": "Při hledání došlo k chybě. Zkontrolujte prosím připojení k internetu nebo to zkuste znovu později.",
- "searchPlaceNames": "Oficiální názvy míst"
+ "searchPlaceNames": "Oficiální názvy míst",
+ "searchMinCharacters_0": "Je třeba zadat minimálně {{count}} znak",
+ "searchMinCharacters_1": "Je třeba zadat minimálně {{count}} znaky",
+ "searchMinCharacters_2": "Je třeba zadat minimálně {{count}} znaků"
},
"terriaViewer": {
"slowWebGLAvailableTitle": "Slabý výkon WebGL",
@@ -730,7 +734,10 @@
"assimp-local-description": "**Upozornění:** Konvertor 3D souborů je experimentální. \nViz seznam [podporovaných formátů](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nSoubory musí být zazipovány.",
"assimp-remote": "Převodník 3D souborů (experimentální)",
"assimp-remote-description": "**Upozornění:** Konvertor 3D souborů je experimentální. \nViz seznam [podporovaných formátů](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nPodporovány jsou také soubory Zip",
- "carto-v3": "Carto V3"
+ "carto-v3": "Carto V3",
+ "i3s": "I3S",
+ "esri-imageServer": "Esri ArcGIS ImageServer (jedna vrstva)",
+ "cesium-ion": "Ionty cesia"
},
"printWindow": {
"errorTitle": "Chyba tisku",
@@ -1304,7 +1311,13 @@
"timeDimensionDisabled": "Čas zakázán (kliknutím povolíte)",
"bulkGeocoderInfoMessage": "CSV obsahuje adresy, ale {{number}} nelze na mapě najít: ",
"bulkGeocoderInfo2Message": "V CSV chybí adresy {{nullAddresses}}.",
- "timeDimensionEnabled": "Čas povolen (kliknutím jej zakážete)"
+ "timeDimensionEnabled": "Čas povolen (kliknutím jej zakážete)",
+ "custom": "Vlastní",
+ "regionMapping": "Mapování regionu",
+ "editStyle": "Upravit Styl",
+ "activeStyle": "Zobrazit proměnnou",
+ "regionColumn": "Sloupec Region",
+ "manualRegionMapping": "Ruční mapování regionu"
},
"terria": {
"loadConfigErrorTitle": "Nepodařilo se načíst konfiguraci mapy Terria",
@@ -1391,7 +1404,7 @@
"missingUrlTitle": "Nelze načíst GetCapabilities",
"missingUrlMessage": "Nepodařilo se načíst dokument GetCapabilities služby WFS (Web Feature Service), protože položka katalogu nemá `url`.",
"noLayerFoundTitle": "Nenalezena žádná vrstva",
- "noLayerFoundMessage": "Datová sada WFS '{{name}}' nemá žádné vrstvy odpovídající '{{typeNames}}'. {{suggested}} {{line}}{{line}}Buď byl katalogový soubor nastaven nesprávně, nebo se změnil server WFS.",
+ "noLayerFoundMessage": "WFS datová sada '{{name}}' nemá žádné vrstvy odpovídající '{{typeNames}}'. Buď byl soubor katalogu nastaven nesprávně, nebo se změnil server WFS.",
"reachedMaxFeatureLimit": "Varování: Tato vrstva dosáhla limitu funkcí WFS ({{maxFeatures}})"
},
"webMapServiceCatalogGroup": {
@@ -1567,6 +1580,515 @@
},
"showClippingBox": "Zobrazit ořezový rámeček",
"keepBoxAboveGround": "Pouze nad zemí"
+ },
+ "tableStyling": {
+ "fill": {
+ "selectableDimensions": {
+ "type": {
+ "name": "Typ",
+ "undefinedLabel": "Prosím upřesněte",
+ "options": {
+ "noStyle": {
+ "name": "Bez stylu"
+ },
+ "sequentialContinuous": {
+ "name": "Sekvenční (průběžný)"
+ },
+ "sequentialDiscrete": {
+ "name": "Sekvenční (diskrétní)"
+ },
+ "divergingContinuous": {
+ "name": "Divergentní (průběžný)"
+ },
+ "divergingDiscrete": {
+ "name": "Divergentní (diskrétní)"
+ },
+ "qualitative": {
+ "name": "Kvalitativní"
+ },
+ "customQualitative": {
+ "name": "Vlastní (kvalitativní)"
+ },
+ "customDiscrete": {
+ "name": "Vlastní (diskrétní)"
+ }
+ }
+ },
+ "tableColorColumn": {
+ "name": "Proměnná"
+ },
+ "dataType": {
+ "name": "Typ sloupce (rozšířený)"
+ },
+ "scheme": {
+ "name": "Schéma"
+ },
+ "numberOfBins": {
+ "name": "Počet zásobníků"
+ }
+ },
+ "name": "Barva výplně"
+ },
+ "hideAdvancedOptions": "Skrýt pokročilé možnosti",
+ "reset": "Obnovit výchozí styl",
+ "copyUserStratum": "Zkopírujte uživatelskou vrstvu do schránky",
+ "data": {
+ "name": "Data",
+ "selectableDimensions": {
+ "tableStyleType": {
+ "name": "Symbologie",
+ "options": {
+ "fill": {
+ "name": "Barva výplně"
+ },
+ "pointSize": {
+ "name": "Velikost bodu"
+ },
+ "point": {
+ "name": "Styl bodu / značky"
+ },
+ "outline": {
+ "name": "Barva obrysu"
+ },
+ "label": {
+ "name": "Styl štítku"
+ },
+ "trail": {
+ "name": "Styl trasy"
+ }
+ }
+ },
+ "tableStyle": {
+ "name": "Styl"
+ },
+ "dataset": {
+ "name": "Datová sada"
+ }
+ }
+ },
+ "name": "Styl",
+ "showAdvancedOptions": "Zobrazit pokročilé možnosti",
+ "bins": {
+ "selectableDimensions": {
+ "start": {
+ "selectableDimensions": {
+ "start": {
+ "name": "Start"
+ },
+ "stop": {
+ "name": "Stop"
+ },
+ "color": {
+ "name": "Barva"
+ }
+ },
+ "name": "{{value1}} až {{value2}}"
+ }
+ },
+ "name": "Zásobníky"
+ },
+ "nullColor": {
+ "name": "Výchozí barva"
+ },
+ "outlierColor": {
+ "name": "Odlehlá barva"
+ },
+ "additionalColors": {
+ "name": "Další barvy",
+ "selectableDimensions": {
+ "nullColor": {
+ "name": "Výchozí barva"
+ },
+ "outlierColor": {
+ "name": "Odlehlá barva"
+ },
+ "regionColor": {
+ "name": "Barva regionu"
+ }
+ }
+ },
+ "pointSize": {
+ "selectableDimensions": {
+ "pointSizeNull": {
+ "name": "Výchozí velikost"
+ },
+ "pointSizeColumn": {
+ "name": "Proměnná"
+ },
+ "pointSizesFactor": {
+ "name": "Faktor velikosti"
+ },
+ "pointSizeOffset": {
+ "name": "Odsazení velikosti"
+ }
+ },
+ "name": "Velikost bodu"
+ },
+ "timeOptions": {
+ "selectableDimensions": {
+ "tableTimeIsSampled": {
+ "options": {
+ "true": {
+ "name": "Ano"
+ },
+ "false": {
+ "name": "Ne"
+ }
+ },
+ "name": "Je vybrán vzorek"
+ },
+ "tableEndTimeColumn": {
+ "name": "Sloupec času ukončení"
+ },
+ "tableTimeIdColumns": {
+ "name": "ID sloupců"
+ },
+ "tableTimeDisplayDuration": {
+ "name": "Doba zobrazení"
+ },
+ "tableTimeSpreadStartTime": {
+ "options": {
+ "true": {
+ "name": "Ano"
+ },
+ "false": {
+ "name": "Ne"
+ }
+ },
+ "name": "Rozptyl času spuštění"
+ },
+ "tableTimeSpreadFinishTime": {
+ "name": "Rozptyl času dokončení",
+ "options": {
+ "true": {
+ "name": "Ano"
+ },
+ "false": {
+ "name": "Ne"
+ }
+ }
+ },
+ "tableTimeColumn": {
+ "name": "Sloupec času"
+ }
+ },
+ "name": "Možnosti času"
+ },
+ "workbenchOptions": {
+ "name": "Možnosti pracovní plochy",
+ "selectableDimensions": {
+ "tableStyleEnalbed": {
+ "name": "Zobrazit styl v pracovní ploše",
+ "options": {
+ "false": {
+ "name": "Styl skrytý"
+ },
+ "true": {
+ "name": "Styl zobrazený"
+ }
+ }
+ },
+ "showDisableStyleOption": {
+ "name": "Zobrazit možnost zakázat styl"
+ },
+ "showDisableTimeOption": {
+ "name": "Zobrazit možnost vypnutí času"
+ },
+ "enableManualRegionMapping": {
+ "name": "Povolit ruční mapování oblastí"
+ }
+ }
+ },
+ "style": {
+ "selectableDimensions": {
+ "bin": {
+ "name": "Koš stylů",
+ "selectableDimensions": {
+ "add": {
+ "value": "Přidat koš stylů"
+ },
+ "bin": {
+ "range": "{{value1}} až {{value2}}",
+ "selectableDimensions": {
+ "remove": {
+ "value": "Odebrat"
+ },
+ "start": {
+ "name": "Start"
+ },
+ "stop": {
+ "name": "Stop"
+ }
+ },
+ "noValue": "Bez hodnoty"
+ }
+ }
+ },
+ "column": {
+ "name": "Proměnná"
+ },
+ "styleType": {
+ "name": "Typ",
+ "undefinedLabel": "Upřesněte prosím",
+ "constant": {
+ "name": "Bez stylu"
+ },
+ "bin": {
+ "name": "Diskrétní"
+ },
+ "enum": {
+ "name": "Kvalitativní"
+ }
+ },
+ "enum": {
+ "selectableDimensions": {
+ "enum": {
+ "noValue": "Žádná hodnota",
+ "selectableDimensions": {
+ "value": {
+ "name": "Hodnota"
+ },
+ "remove": {
+ "value": "Odebrat"
+ }
+ },
+ "add": {
+ "value": "Přidat styl pro hodnotu"
+ }
+ }
+ },
+ "name": "Výčet stylů"
+ }
+ },
+ "null": {
+ "name": "Výchozí"
+ }
+ },
+ "point": {
+ "selectableDimensions": {
+ "height": {
+ "name": "Výška"
+ },
+ "marker": {
+ "name": "Značka",
+ "tooltip": "Marker podporuje URL a base64 libovolného podporovaného formátu obrázku (např. PNG, SVG)"
+ },
+ "rotation": {
+ "name": "Rotace"
+ },
+ "width": {
+ "name": "Šířka"
+ }
+ },
+ "name": "Styl značky"
+ },
+ "label": {
+ "name": "Styl štítku",
+ "selectableDimensions": {
+ "column": {
+ "name": "Sloupec štítku"
+ },
+ "scale": {
+ "name": "Měřítko"
+ },
+ "outlineColor": {
+ "name": "Barva obrysu"
+ },
+ "outlineWidth": {
+ "name": "Šířka obrysu"
+ },
+ "fillColor": {
+ "name": "Barva výplně"
+ },
+ "font": {
+ "name": "Font"
+ },
+ "style": {
+ "name": "Styl štítku",
+ "options": {
+ "fill": {
+ "name": "Pouze výplň"
+ },
+ "outline": {
+ "name": "Pouze obrys"
+ },
+ "fillAndOutline": {
+ "name": "Výplň a obrys"
+ }
+ }
+ },
+ "horizontalOrigin": {
+ "options": {
+ "left": {
+ "name": "Vlevo"
+ },
+ "center": {
+ "name": "Center"
+ },
+ "right": {
+ "name": "Vpravo"
+ }
+ },
+ "name": "Horizontální počátek"
+ },
+ "verticalOrigin": {
+ "name": "Vertikální počátek",
+ "options": {
+ "top": {
+ "name": "Nahoře"
+ },
+ "center": {
+ "name": "Center"
+ },
+ "baseline": {
+ "name": "Baseline"
+ },
+ "bottom": {
+ "name": "Dole"
+ }
+ }
+ },
+ "offsetX": {
+ "name": "Pixel offset X"
+ },
+ "offsetY": {
+ "name": "Pixel offset Y"
+ }
+ }
+ },
+ "trail": {
+ "selectableDimensions": {
+ "trailTime": {
+ "name": "Čas trasy (sekundy)"
+ },
+ "resolution": {
+ "name": "Rozlišení"
+ },
+ "trailStyleOptions": {
+ "selectableDimensions": {
+ "material": {
+ "options": {
+ "solidColor": {
+ "name": "Plná barva"
+ },
+ "polylineGlow": {
+ "name": "Záře polylinií"
+ }
+ },
+ "name": "Typ materiálu"
+ }
+ },
+ "name": "Možnosti stylu trasy"
+ },
+ "width": {
+ "name": "Šířka"
+ },
+ "solidColor": {
+ "name": "Plná barva"
+ },
+ "taperPower": {
+ "name": "Síla kužele"
+ },
+ "growColor": {
+ "name": "Barva záře"
+ },
+ "leadTime": {
+ "name": "Průběžná doba (s)"
+ },
+ "growPower": {
+ "name": "Síla záře"
+ }
+ }
+ },
+ "displayRange": {
+ "name": "Rozsah zobrazení",
+ "selectableDimensions": {
+ "max": {
+ "name": "Max"
+ }
+ }
+ },
+ "colors": {
+ "selectableDimensions": {
+ "value": {
+ "name": "Hodnota"
+ },
+ "remove": {
+ "value": "Odebrat"
+ },
+ "add": {
+ "value": "Přidat barvu"
+ },
+ "color": {
+ "name": "Barva"
+ }
+ },
+ "name": "Barvy"
+ },
+ "legend": {
+ "name": "Legenda",
+ "selectableDimensions": {
+ "legendTitle": {
+ "name": "Název"
+ },
+ "title": {
+ "name": "Název položky {{index}}"
+ },
+ "legendTicks": {
+ "name": "Ticks"
+ }
+ }
+ },
+ "styleOptions": {
+ "name": "Možnosti stylu",
+ "selectableDimensions": {
+ "latitudeColumn": {
+ "name": "Sloupec zeměpisná šířka"
+ },
+ "styleTitle": {
+ "name": "Název"
+ },
+ "longitudeColumn": {
+ "name": "Sloupec zeměpisná délka"
+ }
+ }
+ },
+ "variableAndColumn": {
+ "selectableDimensions": {
+ "columnTitle": {
+ "name": "Název"
+ },
+ "columnUnits": {
+ "name": "Jednotky"
+ }
+ },
+ "name": "Proměnná/sloupec"
+ },
+ "outline": {
+ "selectableDimensions": {
+ "color": {
+ "name": "Barva"
+ },
+ "width": {
+ "name": "Šířka"
+ }
+ },
+ "name": "Styl obrysu"
+ },
+ "min": {
+ "name": "Min"
+ },
+ "regionMapping": {
+ "name": "Mapování regionu"
+ }
+ },
+ "arcGisImageServerCatalogItem": {
+ "invalidServiceMessage": "Při vyvolání služby ArcGIS Image Service došlo k chybě. Odpověď serveru se nezdá být platným dokumentem služby Image Service.",
+ "name": "Esri ArcGIS ImageServer",
+ "invalidUrlTitle": "Nelze načíst ImageServer",
+ "invalidUrlMessage": "Nelze načíst koncový bod ArcGis ImageServer, protože položka katalogu nemá `url`.",
+ "invalidServiceTitle": "Neplatná služba ArcGIS Image Service",
+ "rasterFunction": "Rastrová funkce"
}
},
"deltaTool": {
@@ -1687,5 +2209,28 @@
},
"includeStory": {
"message": "Zahrnout příběh do sdílení"
+ },
+ "relatedMaps": {
+ "buttonText": "Související mapy",
+ "buttonTitle": "Zobrazit související mapy",
+ "panelHeading": "Související mapy",
+ "panelText": "Kliknutím na níže uvedenou mapu ji otevřete v samostatném okně nebo kartě."
+ },
+ "searchProvider": {
+ "models": {
+ "idForMatchingErrorTitle": "Chybějící vlastnost",
+ "idForMatchingErrorMessage": "Objekty modelu musí mít vlastnost `id`, `localId` nebo `name`.",
+ "unsupportedTypeTitle": "Neznámý typ",
+ "unsupportedTypeMessage": "Nepodařilo se vytvořit neznámý typ modelu {{type}}."
+ },
+ "noSearchProviders": "Neexistují žádní nakonfigurovaní poskytovatelé vyhledávání"
+ },
+ "selectableDimensions": {
+ "undefinedLabel": "Neuvedeno",
+ "enabled": "Povoleno",
+ "disabled": "Vypnuto",
+ "colorAdd": "Přidat",
+ "colorRemove": "Odebrat",
+ "invalid": "Neplatné"
}
}
diff --git a/wwwroot/languages/en/translation.json b/wwwroot/languages/en/translation.json
index d5276345530..fe135e3fa8d 100644
--- a/wwwroot/languages/en/translation.json
+++ b/wwwroot/languages/en/translation.json
@@ -202,7 +202,7 @@
"browserPrint": "For better printed results, please use {{appName}}'s Print button instead of your web browser's print feature.",
"shortLinkShortening": "Shortening...",
"shortLinkError": "An error occurred while attempting to shorten the URL. Please check your internet connection and try again.",
- "localDataNote": "<0><0>Note:0>0><1>The following data sources will NOT be shared because they include data from this local system. To share these data sources, publish their data on a web server and <2>add them using a url2>.1>",
+ "localDataNote": "<0><0>Note:0>0><1>The following data sources will NOT be shared because they include data from this local system or from an authenticated online service. To share these data sources, publish their data on a web server and <2>add them using a url2>.1>",
"generatingUrl": "Generating share URL...",
"printTitle": "Print Map",
"printExplanation": "Open a printable version of this map.",
@@ -695,6 +695,7 @@
"wps-getCapabilities": "Web Processing Service (WPS) Server",
"esri-group": "Esri ArcGIS Server",
"esri-mapServer": "Esri ArcGIS MapServer (single layer)",
+ "esri-imageServer": "Esri ArcGIS ImageServer (single layer)",
"esri-featureServer": "Esri ArcGIS FeatureServer (single layer)",
"3d-tiles": "3D Tiles",
"open-street-map": "Open Street Map Server",
@@ -716,7 +717,10 @@
"assimp-local-description": "**Warning:** 3D file converter is experimental. \nSee list of [supported formats](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nFiles must be zipped.",
"assimp-remote": "3D file converter (experimental)",
"assimp-remote-description": "**Warning:** 3D file converter is experimental. \nSee list of [supported formats](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nZip files are also supported",
- "ifc": "IFC"
+ "ifc": "IFC",
+ "cog": "Cloud Optimised Geotiff",
+ "i3s": "I3S",
+ "cesium-ion": "Cesium ion"
},
"printWindow": {
"errorTitle": "Error printing",
@@ -895,6 +899,14 @@
"noLayersFoundTitle": "Could not load ArcGIS MapServer.",
"noLayersFoundMessage": "The Esri ArcGIS MapServer '{{name}}' has no layers to show."
},
+ "arcGisImageServerCatalogItem": {
+ "name": "Esri ArcGIS ImageServer",
+ "invalidUrlTitle": "Unable to load ImageServer",
+ "invalidUrlMessage": "Could not load the ArcGis ImageServer endpoint because the catalog item does not have a `url`.",
+ "invalidServiceTitle": "Invalid ArcGIS Image Service",
+ "invalidServiceMessage": "An error occurred while invoking the ArcGIS Image Service. The server's response does not appear to be a valid Image Service document.",
+ "rasterFunction": "Raster Function"
+ },
"bing": {
"name": "Bing Maps"
},
@@ -2028,6 +2040,9 @@
}
}
}
+ },
+ "cogCatalogItem": {
+ "experimentalReprojectionWarning": "This COG is not in a native projection (EPSG:4326 or EPSG:3857). Reprojecting is experimental and may not work as expected. If you have control of the source data we recommend reprojecting to EPSG:4326 or EPSG:3857 using GDAL or similar."
}
},
"searchProvider": {
diff --git a/wwwroot/languages/es/translation.json b/wwwroot/languages/es/translation.json
index d1dffc7ff32..628eb50233e 100644
--- a/wwwroot/languages/es/translation.json
+++ b/wwwroot/languages/es/translation.json
@@ -35,7 +35,10 @@
"searchErrorOccurred": "Se ha producido un error en la búsqueda. Por favor, compruebe su conexión a internet o inténtelo más tarde.",
"inDataCatalogue": "En el catálogo de datos",
"searchNoCatalogueItem": "Lo sentimos, ningún artículo del catálogo coincide con su búsqueda.",
- "searchNoPlaceNames": "Lo sentimos, ningún topónimo oficial coincide con su búsqueda."
+ "searchNoPlaceNames": "Lo sentimos, ningún topónimo oficial coincide con su búsqueda.",
+ "searchMinCharacters_0": "Necesita introducir al menos {{count}} carácter",
+ "searchMinCharacters_1": "Necesita introducir al menos {{count}} caracteres",
+ "searchMinCharacters_2": "Necesita introducir al menos {{count}} caracteres"
},
"catalogItem": {
"trash": "Quitar del catálogo",
@@ -111,6 +114,303 @@
"contact_point": "Contacto",
"author": "Autor",
"licence": "Licencia"
+ },
+ "webMapServiceCatalogItem": {
+ "getCapabilitiesUrl": "URL GetCapabilities",
+ "serviceDescription": "Descripción del servicio",
+ "serviceContact": "Contacto del servicio",
+ "accessConstraints": "Restricciones de acceso",
+ "noLayerFoundTitle": "Capa no encontrada",
+ "defaultStyleLabel": "Estilo por defecto",
+ "dataDescription": "Descripción de los datos"
+ },
+ "userDrawing": {
+ "messageHeader": "Dibujar en el mapa",
+ "clickToAddFirstPoint": "Haga click para añadir un punto",
+ "btnCancel": "Cancelar",
+ "btnDone": "Hecho",
+ "clickToAddAnotherPoint": "Haga click para añadir otro punto"
+ },
+ "raiseError": {
+ "notificationFeedback": "Para preguntas y comentarios, haga click aquí.",
+ "developerDetails": "Detalles para desarrolladores"
+ },
+ "mapboxVectorTile": {
+ "name": "Teselas vectoriales de Mapbox (MVT)"
+ },
+ "webFeatureServiceCatalogItem": {
+ "noLayerFoundMessage": "El conjunto de dato WFS '{{name}}' no tiene capas que coincidan con '{{typeNames}}'. O el catálogo ha sido configurado erróneamente, o el servidor WFS ha cambiado."
+ },
+ "tableData": {
+ "activeStyle": "Mostrar Variable",
+ "editStyle": "Editar estilo",
+ "noData": "No hay datos que mostrar.",
+ "custom": "Personalizado",
+ "styleDisabledLabel": "Deshabilitar estilo",
+ "bulkGeocoderInfo2Message": "{{nullAddresses}} direcciones faltan en el CSV.",
+ "timeDimensionEnabled": "Opciones temporales activadas (click para deshabilitar)",
+ "legendNullLabel": "(sin valor)",
+ "unsupportedCharactersTitle": "Carácteres erróneos en las columnas de latitud y longitud",
+ "timeDimensionDisabled": "Opciones temporales desactivadas (click para habilitar)",
+ "unsupportedCharactersMessage": "La pareja {{longitude}} (longitud), {{latitude}} (latitud) no pudo ser interpretada",
+ "regionMapping": "Mapeo de regiones",
+ "regionColumn": "Columna de región",
+ "manualRegionMapping": "Mapeo de regiones manual"
+ },
+ "tableStyling": {
+ "reset": "Restaurar estilo por defecto",
+ "name": "Estilo",
+ "showAdvancedOptions": "Mostrar opciones avanzadas",
+ "data": {
+ "name": "Datos",
+ "selectableDimensions": {
+ "tableStyle": {
+ "name": "Estilo"
+ },
+ "tableStyleType": {
+ "name": "Símbolos",
+ "options": {
+ "fill": {
+ "name": "Color de relleno"
+ },
+ "outline": {
+ "name": "Color del borde"
+ }
+ }
+ },
+ "dataset": {
+ "name": "Conjunto de datos"
+ }
+ }
+ },
+ "fill": {
+ "selectableDimensions": {
+ "type": {
+ "options": {
+ "divergingContinuous": {
+ "name": "Divergente (continuo)"
+ },
+ "noStyle": {
+ "name": "Sin estilo"
+ },
+ "sequentialContinuous": {
+ "name": "Secuencial (continuo)"
+ },
+ "sequentialDiscrete": {
+ "name": "Secuencial (discreto)"
+ },
+ "divergingDiscrete": {
+ "name": "Divergente (concreto)"
+ },
+ "qualitative": {
+ "name": "Cualitativo"
+ },
+ "customQualitative": {
+ "name": "Personalizado (cualitativo)"
+ }
+ },
+ "name": "Tipo",
+ "undefinedLabel": "Por favor especifique"
+ },
+ "tableColorColumn": {
+ "name": "Variable"
+ },
+ "dataType": {
+ "name": "Tipo de columna (avanzada)"
+ },
+ "scheme": {
+ "name": "Esquema"
+ },
+ "numberOfBins": {
+ "name": "Número de contenedores"
+ }
+ },
+ "name": "Color de relleno"
+ },
+ "colors": {
+ "selectableDimensions": {
+ "color": {
+ "name": "Color"
+ },
+ "value": {
+ "name": "Valor"
+ },
+ "remove": {
+ "value": "Quitar"
+ }
+ },
+ "name": "Colores"
+ },
+ "additionalColors": {
+ "selectableDimensions": {
+ "nullColor": {
+ "name": "Color por defecto"
+ },
+ "regionColor": {
+ "name": "Color región"
+ },
+ "outlierColor": {
+ "name": "Color valores atípicos"
+ }
+ },
+ "name": "Colores adicionales"
+ },
+ "style": {
+ "selectableDimensions": {
+ "column": {
+ "name": "Variable"
+ }
+ },
+ "null": {
+ "name": "Por defecto"
+ }
+ },
+ "timeOptions": {
+ "selectableDimensions": {
+ "tableTimeColumn": {
+ "name": "Columna temporal"
+ },
+ "tableEndTimeColumn": {
+ "name": "Columna de tiempo final"
+ },
+ "tableTimeIdColumns": {
+ "name": "Columnas de identificador"
+ },
+ "tableTimeIsSampled": {
+ "name": "Es muestreado",
+ "options": {
+ "false": {
+ "name": "No"
+ },
+ "true": {
+ "name": "Sí"
+ }
+ }
+ },
+ "tableTimeDisplayDuration": {
+ "name": "Mostrar duración"
+ },
+ "tableTimeSpreadStartTime": {
+ "options": {
+ "false": {
+ "name": "No"
+ },
+ "true": {
+ "name": "Sí"
+ }
+ },
+ "name": "Unificar fecha inicial datos"
+ },
+ "tableTimeSpreadFinishTime": {
+ "options": {
+ "true": {
+ "name": "Sí"
+ },
+ "false": {
+ "name": "No"
+ }
+ },
+ "name": "Unificar fecha final datos"
+ }
+ },
+ "name": "Opciones temporales"
+ },
+ "hideAdvancedOptions": "Ocultar opciones avanzadas",
+ "copyUserStratum": "Copiar configuración en el portapapeles",
+ "bins": {
+ "name": "Contenedores",
+ "selectableDimensions": {
+ "start": {
+ "name": "Desde {{value1}} hasta {{value2}}",
+ "selectableDimensions": {
+ "color": {
+ "name": "Color"
+ },
+ "start": {
+ "name": "Inicio"
+ },
+ "stop": {
+ "name": "Final"
+ }
+ }
+ }
+ }
+ },
+ "min": {
+ "name": "Mín"
+ },
+ "displayRange": {
+ "name": "Rango de visualización",
+ "selectableDimensions": {
+ "max": {
+ "name": "Máx"
+ }
+ }
+ },
+ "legend": {
+ "name": "Leyenda"
+ },
+ "styleOptions": {
+ "name": "Opciones de estilo",
+ "selectableDimensions": {
+ "styleTitle": {
+ "name": "Título"
+ },
+ "longitudeColumn": {
+ "name": "Columna de longitud"
+ },
+ "latitudeColumn": {
+ "name": "Columna de latitud"
+ }
+ }
+ },
+ "outline": {
+ "name": "Estilo borde",
+ "selectableDimensions": {
+ "color": {
+ "name": "Color"
+ },
+ "width": {
+ "name": "Ancho"
+ }
+ }
+ },
+ "workbenchOptions": {
+ "name": "Opciones del banco de trabajo",
+ "selectableDimensions": {
+ "tableStyleEnalbed": {
+ "name": "Mostrar estilo en el banco de trabajo",
+ "options": {
+ "true": {
+ "name": "Estilo mostrado"
+ },
+ "false": {
+ "name": "Estilo oculto"
+ }
+ }
+ },
+ "showDisableStyleOption": {
+ "name": "Mostrar opción para deshabilitar estilo"
+ },
+ "showDisableTimeOption": {
+ "name": "Mostrar opción para deshabilitar opciones temporales"
+ },
+ "enableManualRegionMapping": {
+ "name": "Permitir mapeo de regiones manual"
+ }
+ }
+ },
+ "variableAndColumn": {
+ "name": "Variable/columna",
+ "selectableDimensions": {
+ "columnTitle": {
+ "name": "Título"
+ },
+ "columnUnits": {
+ "name": "Unidades"
+ }
+ }
+ }
}
},
"analytics": {
@@ -193,9 +493,9 @@
"openFeature": "Zoom a",
"openFeatureTitle": "Zoom al dato",
"colorScaleUpdateRange": "Actualizar Rango",
- "zoomToTitle": "Zoom a la Extensión",
- "opacity": "Opacidad:{{opacity}}%",
- "label": "Conjunto de Datos",
+ "zoomToTitle": "Zoom a la extensión",
+ "opacity": "Opacidad: {{opacity}}%",
+ "label": "Datasets",
"rangeMin": "Mínima:",
"rangeMax": "Máxima:",
"colorScaleRangeMin": "El valor mínimo debe ser un número.",
@@ -203,8 +503,8 @@
"diffImageTitle": "Ver las diferencias de imagen entre dos fechas",
"diffImage": "Diferencia",
"exportDataTitle": "Exportar datos",
- "collapseAll": "Colapsar todo",
- "expandAll": "Ampliar todo",
+ "collapseAll": "Colapsar Todo",
+ "expandAll": "Ampliar Todo",
"toggleVisibility": "Mostrar/ocultar datos",
"zoomTo": "Zoom ideal",
"showMoreActionsTitle": "Mostrar mas acciones",
@@ -235,7 +535,7 @@
"viewLess": "Ver menos resultados de {{name}}",
"placeholder": "Buscar lugares",
"searchCatalogue": "Buscar en el catálogo",
- "searchInDataCatalog": "Buscar <1>'{{locationSearchText}}'1> en el Catálogo de Datos"
+ "searchInDataCatalog": "Buscar '{{locationSearchText}}'en el Catálogo de Datos"
},
"addData": {
"back": "Atrás",
@@ -276,7 +576,7 @@
"titleIII": "Carga de imágenes históricas",
"bodyII": "Es posible que tenga que ajustar el nivel de zoom para que las imágenes por satélite sean visibles en el mapa.",
"bodyIV": "Es posible que las imágenes por satélite no estén siempre disponibles en el momento y lugar que usted prefiera. Si sólo quieres ver las imágenes de una ubicación concreta, haz clic en \"filtrar por ubicación\" en tu banco de datos.",
- "bodyV": "Puedes aplicar una serie de estilos, como el falso color, a las imágenes de satélite haciendo clic en el menú desplegable de estilos de la mesa de trabajo de datos."
+ "bodyV": "Puedes aplicar una serie de estilos, como el falso color, a las imágenes de satélite haciendo clic en el menú desplegable de estilos de el banco de trabajo de datos."
},
"story": {
"story": "Historia",
@@ -287,7 +587,7 @@
"cancelEditing": "Cancelar",
"placeholder": "Introduzca un título aquí"
},
- "removeAllStories": "Eliminar Todos",
+ "removeAllStories": "Eliminar Todas",
"delete": "Eliminar",
"deleteStory": "borrar",
"edit": "Editar",
@@ -299,12 +599,13 @@
"gettingStarted": "Empezar",
"gettingStartedTitle": "Empezar",
"share": "Compartir",
- "collapse": "Colapso",
+ "collapse": "Colapsar",
"badgeBarLabel": "Escenas",
"untitledScene": "escena sin título",
"doesNotExist": "La historia no existe",
- "removeAllStoriesDialog": "¿Está seguro de que desea eliminar la escena {{ count }}?",
- "removeAllStoriesDialog_plural": "¿Está seguro de que desea eliminar las escenas {{ count }}?",
+ "removeAllStoriesDialog_0": "¿Está seguro de que desea eliminar {{ count }} escena?",
+ "removeAllStoriesDialog_1": "¿Está seguro de que desea eliminar las {{ count }} escenas?",
+ "removeAllStoriesDialog_2": "",
"panelBody": "Crea y comparte historias interactivas directamente desde tu mapa",
"recapture": "Recaptura",
"recaptureStory": "volver a capturar",
@@ -342,7 +643,7 @@
"btnCloseFeature": "Cerrar el panel de dato",
"panelHeading": "Información del Elemento",
"userSelection": "Selección de usuario",
- "clickToAddData": "Pinche'$t(addData.addDataBtnText)' para añadir dato al mapa.",
+ "clickToAddData": "Pinche '$t(addData.addDataBtnText)' para añadir datos al mapa.",
"noDataAvailable": "No hay datos disponibles aquí - pruebe otra localización.",
"clickMap": "Pinchar en el mapa para conocer más sobre esta localización",
"pickLocation": "Elegir localización",
@@ -376,7 +677,7 @@
"location": "Localización",
"myLocation": "Mi localización",
"browserCannotProvide": "Su navegador no puede proporcionar su localización.",
- "originError": "Su navegador solo puede proveer su localización cuando usa HTTPS. Usted posible que usar {{secureUrl}} en su lugar."
+ "originError": "Su navegador solo puede proveer su localización cuando usa HTTPS. Puede utilizar {{secureUrl}} en su lugar."
},
"countDatasets": {
"loadError": "No se pudo cargar.",
@@ -441,13 +742,13 @@
"balancedPerformance": "Balance entre rendimiento y calidad",
"maximumPerformance": "Máximo rendimiento, baja calidad"
},
- "mapQuality": "Calidad del Mapa Ráster:",
+ "mapQuality": "Calidad del Mapa:",
"nativeResolutionHeader": "Usar resolución nativa del dispositivo",
"btnTitle": "Cambiar vista",
"baseMap": "Mapa Base",
"timeline": {
- "alwaysShowLabel": "Pulse empezar a mostrar la línea de tiempo sólo cuando haya conjuntos de datos que varíen en el tiempo en la mesa de trabajo",
- "hideLabel": "Pulse para que se muestre siempre la línea de tiempo, aunque no haya conjuntos de datos que varíen en el tiempo en la mesa de trabajo",
+ "alwaysShowLabel": "Pulse empezar a mostrar la línea de tiempo sólo cuando haya conjuntos de datos que varíen en el tiempo en el banco de trabajo",
+ "hideLabel": "Pulse para que se muestre siempre la línea de tiempo, aunque no haya conjuntos de datos que varíen en el tiempo el banco de trabajo",
"title": "Línea de tiempo",
"alwaysShow": "Siempre mostrar"
},
@@ -545,7 +846,8 @@
"selectToPreviewDataset": "Seleccione un conjunto de datos para ver una vista previa",
"selectToPreviewSeparator": "O",
"goToTheMap": "Vaya al mapa",
- "noPreviewAvailable": "NO HAY VISTA PREVIA DISPONIBLE"
+ "noPreviewAvailable": "NO HAY VISTA PREVIA DISPONIBLE",
+ "selectMultipleDatasets": "<0>Pulse Mayus y haga click0><1 /><2>para añadir múltiples conjuntos de datos2>"
},
"description": {
"typeName": "Nombre del tipo",
@@ -581,7 +883,7 @@
"preface": {
"title": "Hacer el recorrido",
"close": "Tal vez más tarde",
- "content": "¿No está seguro por dónde comenzar? Haga un recorrido rápido por las funciones principales de nuestro software y aprenda algunas de las funciones clave para ayudarlo en su camino.",
+ "content": "¿No está seguro por dónde comenzar? Haga un recorrido rápido por las funciones principales de nuestro software y conozca algunas de las funciones clave para ayudarlo en su camino.",
"start": "Empezar Tour"
},
"locationSearchInput": {
@@ -592,7 +894,7 @@
"content": "## Historias\nLas historias permiten añadir información contextual a un conjunto de datos para dar vida a una narración. Cree su propia historia de datos con el Editor de Historias y compártala a través del panel \"Compartir\" una vez que haya terminado."
},
"exploreMapDataButton": {
- "content": "## Explorar datos del mapa\nBusca en el catálogo datos disponibles y agrega al mapa aquí. Tu puedes agregar múltiples set de datos en cualquier momento, y verás a ellos en el listado abajo"
+ "content": "## Explore datos del mapa\n\nRecorra el catálogo de datos disponibles y agréguelos al mapa desde aquí. Puede agregar múltiples conjuntos de datos en cualquier momento, y los verá listados debajo en el Tablero."
},
"menuBarMapSettingsButton": {
"content": "## Configuraciones de mapa\nPersonalice los ajustes de los mapas, como los mapas base, el terreno 2D/3D y la calidad de la imagen del mapa para mejorar el rendimiento."
@@ -713,9 +1015,9 @@
"emptyWorkbench": {
"helpfulHints": "Consejos útiles",
"emptyArea": "Su banco de trabajo está vacío",
- "helpfulHintsOne": "Busque los datos disponibles seleccionando \"Explorar datos del mapa\" o haga clic en \"Cargar\" para añadir sus propios datos al mapa.",
+ "helpfulHintsOne": "Busque los datos disponibles seleccionando \"Explorar los datos del mapa\" o haga clic en \"Subir\" para añadir sus propios datos al mapa.",
"helpfulHintsTwo": "Una vez que hayas añadido datos al mapa, tus conjuntos de datos activos aparecerán aquí en tu banco de trabajo. El banco de trabajo le ayudará a interactuar con los datos.",
- "helpfulHintsThree": "En la mesa de trabajo puede activar y desactivar conjuntos de datos, cambiar su opacidad, activar la comparación en pantalla dividida, cambiar estilos y navegar por fechas y horas, si los datos admiten esta funcionalidad."
+ "helpfulHintsThree": "En el banco de trabajo puede activar y desactivar conjuntos de datos, cambiar su opacidad, activar la comparación en pantalla dividida, cambiar estilos y navegar por fechas y horas, si los datos admiten esta funcionalidad."
},
"timer": {
"nextScheduledUpdateTime": "Próxima actualización de datos a {{scheduledUpdateTime}}",
@@ -771,7 +1073,9 @@
"assimp-local": "Convertidor de archivos 3D (zip) (experimental)",
"assimp-local-description": "**Atención:** El convertidor de archivos 3D es experimental.\nVer lista de [formatos soportados](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nLos archivos deben estar comprimidos.",
"assimp-remote": "Convertidor de archivos 3D (experimental)",
- "assimp-remote-description": "**Atención:** El convertidor de archivos 3D es experimental.\nConsulte la lista de [formatos compatibles](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nTambién se admiten archivos Zip"
+ "assimp-remote-description": "**Atención:** El convertidor de archivos 3D es experimental.\nConsulte la lista de [formatos compatibles](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). \nTambién se admiten archivos Zip",
+ "esri-imageServer": "Esri ArcGIS ImageServer (capa única)",
+ "i3s": "I3S"
},
"printWindow": {
"errorTitle": "Error de impresión",
@@ -822,7 +1126,8 @@
"devError": "cesium es requerido",
"failedToObtain": "No se pudo obtener la imagen X: {{x}} Y: {{y}} Nivel: {{level}}.",
"notWebMercatorTilingScheme": "Este conjunto de datos no puede mostrarse en el mapa 2D porque no es compatible con la proyección Web Mercator (EPSG:3857).",
- "unusalTilingScheme": "Este conjunto de datos no puede mostrarse en el mapa 2D porque no es compatible con la proyección Web Mercator (EPSG:3857)."
+ "unusalTilingScheme": "Este conjunto de datos no puede mostrarse en el mapa 2D porque no es compatible con la proyección Web Mercator (EPSG:3857).",
+ "terrainServerErrorMessage": " El servidor de terreno no responde por el momento. Puede seguir utilizando todas las functiones de {{appName}} pero no habrá detalles de terreno en el modo 3D. Lamentamos los inconvenientes ocasionados. Por favor intente nuevamente más tarde, el servidor debería responder correctamente. Si el problema continúa contáctese por correo electrónico a {{supportEmail}}."
},
"displayVariablesConcept": {
"defaultName": "Visualización de la variable"
@@ -866,7 +1171,60 @@
"devError": "No hay contexto para la recoloracion de imágenes"
},
"mapboxVectorTileImageryProvider": {
- "requireLayerName": "CajademapaVectorTileProveedorimagenes requiere un nombre de capa pasado como options.normbrecapa"
+ "requireLayerName": "CajademapaVectorTileProveedorimagenes requiere un nombre de capa pasado como options.normbrecapa",
+ "requireStyles": "MapboxVectorTileImageryProvider requiere una función de estilo como parámetro en options.styleFunc"
+ },
+ "extraCreditLinks": {
+ "dataAttribution": "Atribución de los datos",
+ "disclaimer": "Descargo de responsabilidad"
+ }
+ },
+ "relatedMaps": {
+ "buttonText": "Mapas relacionados",
+ "buttonTitle": "Ver mapas relacionados",
+ "panelHeading": "Mapas relacionados",
+ "panelText": "Hacer click en el mapa inferior lo abrirá en una ventana o pestaña separadas."
+ },
+ "compare": {
+ "done": "Hecho"
+ },
+ "selectableDimensions": {
+ "undefinedLabel": "No especificado",
+ "colorAdd": "Añadir",
+ "enabled": "Activado",
+ "colorRemove": "Quitar",
+ "disabled": "Deshabilitado"
+ },
+ "deltaTool": {
+ "titlePrefix": "Detección de cambio",
+ "generateDeltaBtn": "Generar mapa de diferencia",
+ "loadingError": {
+ "title": "Error al cargar la herramienta Delta",
+ "message": "Se produjo un error al intentar cargar la herramienta Delta desde el servidor. Por favor, inténtelo de nuevo."
+ },
+ "cancelBtn": "Cancelar",
+ "secondaryImage": "Imagen secundaria",
+ "selectedLocation": "Lugar Seleccionado",
+ "description": "Esta herramienta visualiza la diferencia entre las imágenes capturadas en dos puntos discretos en el tiempo.",
+ "pickLocation": "Para ver las imágenes disponibles, seleccione su ubicación de interés en el mapa opuesto.",
+ "pickerMessage": {
+ "pickFirst": "Seleccione un punto haciendo clic en el mapa.",
+ "pickAnother": "Haga clic en otro punto para cambiar la selección",
+ "pickError": "¡Error al intentar recuperar las imágenes de la ubicación! Por favor, seleccione un punto de nuevo haciendo clic en el mapa."
+ },
+ "catalogItem": {
+ "description": "Esta capa visualiza la diferencia entre las imágenes capturadas en dos puntos discretos en el tiempo"
+ },
+ "primaryImage": "Imagen primaria"
+ },
+ "mapNavigation": {
+ "additionalTools": "Herramientas adicionales"
+ },
+ "pedestrianMode": {
+ "toolButtonTitle": "Modo Peatón",
+ "dropPedestrianTooltipMessage": "Click izquierdo para seleccionarClick derecho / Esc para cancelar",
+ "controls": {
+ "title": "Controles"
}
}
}
diff --git a/wwwroot/languages/eu/translation.json b/wwwroot/languages/eu/translation.json
new file mode 100644
index 00000000000..0967ef424bc
--- /dev/null
+++ b/wwwroot/languages/eu/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/wwwroot/languages/id/translation.json b/wwwroot/languages/id/translation.json
index 350a2486504..6312e5bd6f7 100644
--- a/wwwroot/languages/id/translation.json
+++ b/wwwroot/languages/id/translation.json
@@ -297,7 +297,18 @@
},
"compass": {
"guidanceBtnText": "Lihat petunjuk lengkap tentang bagaimana cara menggunakan kompas",
- "title": "Klik dan seret untuk memutar kamera"
+ "title": "Klik dan seret untuk memutar kamera",
+ "guidance": {
+ "title": "Kontrol Giroskop",
+ "innerCircleDescription1": "Klik di bagian tengah dan seret perlahan ke atas, bawah, kiri atau kanan untuk memiringkan dan memutar peta secara bersamaan.",
+ "innerCircleDescription2": "Klik dua kali di sini untuk mengatur ulang tampilan ke kondisi default.",
+ "ctrlDragDescription": "Anda juga dapat memiringkan dan memutar peta dengan menahan tombol CTRL dan menyeret peta.",
+ "outerRingTitle": "Cincin Luar",
+ "outerRingDescription": "Seret cincin luar dengan gerakan melingkar untuk memutar tampilan peta 360˚.",
+ "innerCircleTitle": "Lingkaran Dalam"
+ },
+ "description": "Seret cincin luar: memutar tampilan. \nSeret giroskop bagian dalam: membebaskan orbit. \nKlik dua kali: mengatur ulang tampilan. \nTIPS: Anda juga dapat membebaskan orbit dengan menahan tombol CTRL dan menyeret peta.",
+ "guidanceBtnTitle": "Panduan Giroskop"
},
"zoomCotrol": {
"zoomOut": "Perkecil",
@@ -319,7 +330,8 @@
"duplicateModelErrorMessage": "Terjadi error saat memisahkan item katalog`\"{{name}}\"`. Item katalog ini mungkin tidak mendukung fungsionalitas \"bandingkan\"",
"modelNotFoundErrorMessage": "ID Model `\"{{id}}\"` tidak ditemukan",
"toggleSplitterTool": "Aktifkan perbandingan berdampingan antara dua set data yang berbeda",
- "toggleSplitterToolDisabled": "Harap nonaktifkan fitur perbandingan berdampingan lainnya untuk mengaktifkan perbandingan standar"
+ "toggleSplitterToolDisabled": "Harap nonaktifkan fitur perbandingan berdampingan lainnya untuk mengaktifkan perbandingan standar",
+ "title": "Seret ke kiri atau ke kanan untuk menyesuaikan tampilan"
},
"location": {
"originError": "Browser Anda hanya dapat memberikan lokasi Anda saat menggunakan HTTPS. Anda mungkin dapat menggunakan {{secureUrl}} sebagai gantinya.",
diff --git a/wwwroot/test/ArcGisImageServer/rasterFns/imageserver.json b/wwwroot/test/ArcGisImageServer/rasterFns/imageserver.json
new file mode 100644
index 00000000000..7cd10b579d2
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/rasterFns/imageserver.json
@@ -0,0 +1,300 @@
+{
+ "currentVersion": 10.91,
+ "serviceDescription": "Some service description",
+ "name": "Some name",
+ "description": "Some description",
+ "extent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "initialExtent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "fullExtent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "hasMultidimensions": false,
+ "pixelSizeX": 10,
+ "pixelSizeY": 10,
+ "datasetFormat": "AMD",
+ "uncompressedSize": 9000000,
+ "blockWidth": 2048,
+ "blockHeight": 256,
+ "compressionType": "None",
+ "bandNames": ["Some Band Name"],
+ "allowCopy": true,
+ "allowAnalysis": true,
+ "bandCount": 1,
+ "pixelType": "F32",
+ "minPixelSize": 0,
+ "maxPixelSize": 0,
+ "copyrightText": "Some Copyright",
+ "serviceDataType": "esriImageServiceDataTypeElevation",
+ "serviceSourceType": "esriImageServiceSourceTypeMosaicDataset",
+ "minValues": [515.6699829101562],
+ "maxValues": [1611.125],
+ "meanValues": [712.371337411377],
+ "stdvValues": [45.56883666949917],
+ "objectIdField": "OBJECTID",
+ "fields": [
+ {
+ "name": "OBJECTID",
+ "type": "esriFieldTypeOID",
+ "alias": "OBJECTID",
+ "domain": null
+ },
+ {
+ "name": "Shape",
+ "type": "esriFieldTypeGeometry",
+ "alias": "Shape",
+ "domain": null
+ },
+ {
+ "name": "Name",
+ "type": "esriFieldTypeString",
+ "alias": "Name",
+ "domain": null,
+ "length": 50
+ },
+ {
+ "name": "MinPS",
+ "type": "esriFieldTypeDouble",
+ "alias": "MinPS",
+ "domain": null
+ },
+ {
+ "name": "MaxPS",
+ "type": "esriFieldTypeDouble",
+ "alias": "MaxPS",
+ "domain": null
+ },
+ {
+ "name": "LowPS",
+ "type": "esriFieldTypeDouble",
+ "alias": "LowPS",
+ "domain": null
+ },
+ {
+ "name": "HighPS",
+ "type": "esriFieldTypeDouble",
+ "alias": "HighPS",
+ "domain": null
+ },
+ {
+ "name": "Category",
+ "type": "esriFieldTypeInteger",
+ "alias": "Category",
+ "domain": {
+ "type": "codedValue",
+ "name": "MosaicCatalogItemCategoryDomain",
+ "description": "Catalog item categories.",
+ "codedValues": [
+ {
+ "name": "Unknown",
+ "code": 0
+ },
+ {
+ "name": "Primary",
+ "code": 1
+ },
+ {
+ "name": "Overview",
+ "code": 2
+ },
+ {
+ "name": "Unprocessed Overview",
+ "code": 3
+ },
+ {
+ "name": "Partial Overview",
+ "code": 4
+ },
+ {
+ "name": "Uploaded",
+ "code": 253
+ },
+ {
+ "name": "Incomplete",
+ "code": 254
+ },
+ {
+ "name": "Custom",
+ "code": 255
+ }
+ ],
+ "mergePolicy": "esriMPTDefaultValue",
+ "splitPolicy": "esriSPTDefaultValue"
+ }
+ },
+ {
+ "name": "Tag",
+ "type": "esriFieldTypeString",
+ "alias": "Tag",
+ "domain": null,
+ "length": 20
+ },
+ {
+ "name": "GroupName",
+ "type": "esriFieldTypeString",
+ "alias": "GroupName",
+ "domain": null,
+ "length": 50
+ },
+ {
+ "name": "ProductName",
+ "type": "esriFieldTypeString",
+ "alias": "ProductName",
+ "domain": null,
+ "length": 50
+ },
+ {
+ "name": "CenterX",
+ "type": "esriFieldTypeDouble",
+ "alias": "CenterX",
+ "domain": null
+ },
+ {
+ "name": "CenterY",
+ "type": "esriFieldTypeDouble",
+ "alias": "CenterY",
+ "domain": null
+ },
+ {
+ "name": "ZOrder",
+ "type": "esriFieldTypeInteger",
+ "alias": "ZOrder",
+ "domain": null
+ },
+ {
+ "name": "Shape_Length",
+ "type": "esriFieldTypeDouble",
+ "alias": "Shape_Length",
+ "domain": null
+ },
+ {
+ "name": "Shape_Area",
+ "type": "esriFieldTypeDouble",
+ "alias": "Shape_Area",
+ "domain": null
+ },
+ {
+ "name": "Version",
+ "type": "esriFieldTypeString",
+ "alias": "Version",
+ "domain": null,
+ "length": 20
+ },
+ {
+ "name": "PointCount",
+ "type": "esriFieldTypeDouble",
+ "alias": "Point Count",
+ "domain": null
+ },
+ {
+ "name": "PointSpacing",
+ "type": "esriFieldTypeDouble",
+ "alias": "Point Spacing",
+ "domain": null
+ },
+ {
+ "name": "ZMin",
+ "type": "esriFieldTypeDouble",
+ "alias": "ZMin",
+ "domain": null
+ },
+ {
+ "name": "ZMax",
+ "type": "esriFieldTypeDouble",
+ "alias": "ZMax",
+ "domain": null
+ }
+ ],
+ "capabilities": "Image,Metadata,Catalog,Mensuration",
+ "defaultMosaicMethod": "Northwest",
+ "allowedMosaicMethods": "NorthWest,Center,LockRaster,ByAttribute,Nadir,Viewpoint,Seamline,None",
+ "sortField": "",
+ "sortValue": null,
+ "sortAscending": true,
+ "mosaicOperator": "First",
+ "maxDownloadSizeLimit": 0,
+ "defaultCompressionQuality": 10000,
+ "defaultResamplingMethod": "Bilinear",
+ "maxImageHeight": 4100,
+ "maxImageWidth": 15000,
+ "maxRecordCount": 1000,
+ "maxDownloadImageCount": 0,
+ "maxMosaicImageCount": 20,
+ "allowRasterFunction": true,
+ "rasterFunctionInfos": [
+ {
+ "name": "None",
+ "description": "Make a Raster or Raster Dataset into a Function Raster Dataset.",
+ "help": ""
+ },
+ {
+ "name": "RFTAspectColor",
+ "description": "This function generates a color representation of aspect."
+ },
+ {
+ "name": "RFTHillshade",
+ "description": "This function creates a hillshade effect based on the elevation data source.",
+ "help": ""
+ },
+ {
+ "name": "RFTShadedReliefElevationColorRamp",
+ "description": "This function processes the elevation surface as shaded relief. ",
+ "help": "This raster function template uses a shaded relief function.."
+ }
+ ],
+ "rasterTypeInfos": [
+ {
+ "name": "Raster Dataset",
+ "description": "Supports all ArcGIS Raster Datasets",
+ "help": ""
+ }
+ ],
+ "mensurationCapabilities": "Basic",
+ "hasHistograms": true,
+ "hasColormap": false,
+ "hasRasterAttributeTable": false,
+ "minScale": 0,
+ "maxScale": 0,
+ "exportTilesAllowed": false,
+ "supportsStatistics": true,
+ "supportsAdvancedQueries": true,
+ "editFieldsInfo": null,
+ "ownershipBasedAccessControlForRasters": null,
+ "allowComputeTiePoints": false,
+ "useStandardizedQueries": true,
+ "advancedQueryCapabilities": {
+ "useStandardizedQueries": true,
+ "supportsStatistics": true,
+ "supportsOrderBy": true,
+ "supportsDistinct": true,
+ "supportsPagination": true
+ },
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+}
diff --git a/wwwroot/test/ArcGisImageServer/rasterFns/legend.json b/wwwroot/test/ArcGisImageServer/rasterFns/legend.json
new file mode 100644
index 00000000000..e293b958014
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/rasterFns/legend.json
@@ -0,0 +1,38 @@
+{
+ "layers": [
+ {
+ "layerId": 0,
+ "layerName": "Layer Name",
+ "layerType": "Raster Layer",
+ "minScale": 0,
+ "maxScale": 0,
+ "legendType": "Stretched",
+ "legend": [
+ {
+ "label": "High : Some value",
+ "url": "a758ed6a2eb93b3f835ab3a17f21dfda",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAT0lEQVQ4je3RwQkAMAgDwAjiz/1XVUTtEE1/zQCHibK7C1JmRjQiWB7MDJqZXJB5obtzQQDQquKCzA0BPKhMB+mV6U/5G96Df8PrSHdTwQOUlT8HeNXIpAAAAABJRU5ErkJggg==",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "Some label",
+ "url": "b0b4583afdd50894cc0738805356a037",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAUElEQVQ4je3UwQkAMQhE0S+kbcGyjSK7RWQOOWQKeMgMaO7+IUpE2MpMlQfA2ntrQfmF3a0FX4fn4P0dVpUWvH/l1+FxDJB97JkxmxmVB8APVtY8xR14rRcAAAAASUVORK5CYII=",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "Low : Some value",
+ "url": "92a46f91e372e90744ce1a7d03335211",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAIUlEQVQ4jWP8+/cvAzUBE1VNGzVw1MBRA0cNHDVwCBkIAEMfAx/78kANAAAAAElFTkSuQmCC",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ }
+ ]
+ }
+ ]
+}
diff --git a/wwwroot/test/ArcGisImageServer/tile/identify.json b/wwwroot/test/ArcGisImageServer/tile/identify.json
new file mode 100644
index 00000000000..611d2522202
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/tile/identify.json
@@ -0,0 +1,13 @@
+{
+ "objectId": 0,
+ "name": "Pixel",
+ "value": "178, 135, 99, 255",
+ "location": {
+ "x": 15865828.500025423,
+ "y": -2553895.2233379674,
+ "spatialReference": { "wkid": 102100, "latestWkid": 3857 }
+ },
+ "properties": null,
+ "catalogItems": null,
+ "catalogItemVisibilities": []
+}
diff --git a/wwwroot/test/ArcGisImageServer/tile/imageserver.json b/wwwroot/test/ArcGisImageServer/tile/imageserver.json
new file mode 100644
index 00000000000..6ebccccfb43
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/tile/imageserver.json
@@ -0,0 +1,220 @@
+{
+ "currentVersion": 10.91,
+ "serviceDescription": "Some service description.",
+ "name": "Some name",
+ "description": "Some description",
+ "extent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "initialExtent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "fullExtent": {
+ "xmin": -1.3873971544712003e7,
+ "ymin": 5151008.633437126,
+ "xmax": -1.2960958413099812e7,
+ "ymax": 5831188.605321072,
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+ },
+ "pixelSizeX": 0.298582141647617,
+ "pixelSizeY": 0.2985821416476171,
+ "bandCount": 3,
+ "pixelType": "U8",
+ "minPixelSize": 0.29858214164761643,
+ "maxPixelSize": 1222.9924525624938,
+ "copyrightText": "Some copyright",
+ "serviceDataType": "esriImageServiceDataTypeRGB",
+ "minValues": [],
+ "maxValues": [],
+ "meanValues": [],
+ "stdvValues": [],
+ "objectIdField": "",
+ "fields": [],
+ "capabilities": "Mensuration,Image,Metadata",
+ "defaultMosaicMethod": "Center",
+ "allowedMosaicMethods": "",
+ "sortField": "",
+ "sortValue": null,
+ "sortAscending": true,
+ "mosaicOperator": "First",
+ "defaultCompressionQuality": 75,
+ "defaultResamplingMethod": "Bilinear",
+ "maxImageHeight": 4100,
+ "maxImageWidth": 15000,
+ "singleFusedMapCache": true,
+ "tileInfo": {
+ "rows": 256,
+ "cols": 256,
+ "dpi": 96,
+ "format": "MIXED",
+ "compressionQuality": 75,
+ "origin": {
+ "x": -2.0037508342787e7,
+ "y": 2.0037508342787e7
+ },
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ },
+ "lods": [
+ {
+ "level": 0,
+ "resolution": 156543.033928,
+ "scale": 5.91657527591555e8
+ },
+ {
+ "level": 1,
+ "resolution": 78271.5169639999,
+ "scale": 2.95828763795777e8
+ },
+ {
+ "level": 2,
+ "resolution": 39135.7584820001,
+ "scale": 1.47914381897889e8
+ },
+ {
+ "level": 3,
+ "resolution": 19567.8792409999,
+ "scale": 7.3957190948944e7
+ },
+ {
+ "level": 4,
+ "resolution": 9783.93962049996,
+ "scale": 3.6978595474472e7
+ },
+ {
+ "level": 5,
+ "resolution": 4891.96981024998,
+ "scale": 1.8489297737236e7
+ },
+ {
+ "level": 6,
+ "resolution": 2445.98490512499,
+ "scale": 9244648.868618
+ },
+ {
+ "level": 7,
+ "resolution": 1222.99245256249,
+ "scale": 4622324.434309
+ },
+ {
+ "level": 8,
+ "resolution": 611.49622628138,
+ "scale": 2311162.217155
+ },
+ {
+ "level": 9,
+ "resolution": 305.748113140558,
+ "scale": 1155581.108577
+ },
+ {
+ "level": 10,
+ "resolution": 152.874056570411,
+ "scale": 577790.554289
+ },
+ {
+ "level": 11,
+ "resolution": 76.4370282850732,
+ "scale": 288895.277144
+ },
+ {
+ "level": 12,
+ "resolution": 38.2185141425366,
+ "scale": 144447.638572
+ },
+ {
+ "level": 13,
+ "resolution": 19.1092570712683,
+ "scale": 72223.819286
+ },
+ {
+ "level": 14,
+ "resolution": 9.55462853563415,
+ "scale": 36111.909643
+ },
+ {
+ "level": 15,
+ "resolution": 4.77731426794937,
+ "scale": 18055.954822
+ },
+ {
+ "level": 16,
+ "resolution": 2.38865713397468,
+ "scale": 9027.977411
+ },
+ {
+ "level": 17,
+ "resolution": 1.19432856685505,
+ "scale": 4513.988705
+ },
+ {
+ "level": 18,
+ "resolution": 0.597164283559817,
+ "scale": 2256.994353
+ },
+ {
+ "level": 19,
+ "resolution": 0.298582141647617,
+ "scale": 1128.497176
+ }
+ ]
+ },
+ "cacheType": "Map",
+ "allowRasterFunction": true,
+ "rasterFunctionInfos": [
+ {
+ "name": "None",
+ "description": "",
+ "help": ""
+ }
+ ],
+ "rasterTypeInfos": [
+ {
+ "name": "Raster Dataset",
+ "description": "Supports all ArcGIS Raster Datasets",
+ "help": ""
+ }
+ ],
+ "mensurationCapabilities": "Basic",
+ "hasHistograms": false,
+ "hasColormap": false,
+ "hasRasterAttributeTable": false,
+ "minScale": 4622324.434309,
+ "maxScale": 1128.497176,
+ "exportTilesAllowed": false,
+ "hasMultidimensions": false,
+ "supportsStatistics": false,
+ "supportsAdvancedQueries": false,
+ "editFieldsInfo": null,
+ "ownershipBasedAccessControlForRasters": null,
+ "allowComputeTiePoints": false,
+ "useStandardizedQueries": true,
+ "advancedQueryCapabilities": {
+ "useStandardizedQueries": true,
+ "supportsStatistics": false,
+ "supportsOrderBy": false,
+ "supportsDistinct": false,
+ "supportsPagination": false
+ },
+ "spatialReference": {
+ "wkid": 102100,
+ "latestWkid": 3857
+ }
+}
diff --git a/wwwroot/test/ArcGisImageServer/tile/legend.json b/wwwroot/test/ArcGisImageServer/tile/legend.json
new file mode 100644
index 00000000000..d3f4a619a2f
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/tile/legend.json
@@ -0,0 +1,38 @@
+{
+ "layers": [
+ {
+ "layerId": 0,
+ "layerName": "Some tiled layer",
+ "layerType": "Raster Layer",
+ "minScale": 0,
+ "maxScale": 0,
+ "legendType": "RGB Composite",
+ "legend": [
+ {
+ "label": "Red: Band_1",
+ "url": "2929cfae2efac980ef6c9ea09223463e",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAANUlEQVQ4jWPMy8v7z0BFwMLAwMAwcdIkqhiWn5fHwEQVk5DAqIGjBo4aOGrgqIEQwEjtKgAATl0Hu6JrzFUAAAAASUVORK5CYII=",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "Green: Band_2",
+ "url": "49f1c6a1be24c5484bbf3e629796273e",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAANUlEQVQ4jWPMy8v7z0BFwMLAwMAwaeIkqhiWl5/HwEQVk5DAqIGjBo4aOGrgqIEQwEjtKgAATl0Hu6sKxboAAAAASUVORK5CYII=",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "Blue: Band_3",
+ "url": "ea7072b100ba7bef3760e98b91c4313f",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAANUlEQVQ4jWPMy8v7z0BFwMLAwMAwadJEqhiWl5fPwEQVk5DAqIGjBo4aOGrgqIEQwEjtKgAATl0Hu75+IUcAAAAASUVORK5CYII=",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ }
+ ]
+ }
+ ]
+}
diff --git a/wwwroot/test/ArcGisImageServer/time/identify.json b/wwwroot/test/ArcGisImageServer/time/identify.json
new file mode 100644
index 00000000000..560bd9f07ac
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/time/identify.json
@@ -0,0 +1,13 @@
+{
+ "objectId": 0,
+ "name": "Pixel",
+ "value": "8",
+ "location": {
+ "x": 128.2904493061971,
+ "y": -18.296866690954595,
+ "spatialReference": { "wkid": 4326, "latestWkid": 4326 }
+ },
+ "properties": null,
+ "catalogItems": null,
+ "catalogItemVisibilities": []
+}
diff --git a/wwwroot/test/ArcGisImageServer/time/imageserver.json b/wwwroot/test/ArcGisImageServer/time/imageserver.json
new file mode 100644
index 00000000000..10f7f0c86b0
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/time/imageserver.json
@@ -0,0 +1,121 @@
+{
+ "currentVersion": 10.91,
+ "serviceDescription": "Some service description.",
+ "name": "Some name",
+ "description": "Some description",
+ "extent": {
+ "xmin": -180.3125,
+ "ymin": -90.25,
+ "xmax": 179.6875,
+ "ymax": 90.25,
+ "spatialReference": {
+ "wkid": 4326,
+ "latestWkid": 4326
+ }
+ },
+ "initialExtent": {
+ "xmin": -180.3125,
+ "ymin": -90.25,
+ "xmax": 179.6875,
+ "ymax": 90.25,
+ "spatialReference": {
+ "wkid": 4326,
+ "latestWkid": 4326
+ }
+ },
+ "fullExtent": {
+ "xmin": -180.3125,
+ "ymin": -90.25,
+ "xmax": 179.6875,
+ "ymax": 90.25,
+ "spatialReference": {
+ "wkid": 4326,
+ "latestWkid": 4326
+ }
+ },
+ "hasMultidimensions": true,
+ "timeInfo": {
+ "startTimeField": "StdTime",
+ "endTimeField": "StdTime",
+ "timeExtent": [378604800000, 1640882880000],
+ "timeReference": null,
+ "defaultTimeInterval": 365.2425,
+ "defaultTimeIntervalUnits": "esriTimeUnitsDays"
+ },
+ "pixelSizeX": 0.5,
+ "pixelSizeY": 0.5,
+ "datasetFormat": "Cache/LERC2D",
+ "uncompressedSize": 2079360,
+ "blockWidth": 256,
+ "blockHeight": 256,
+ "compressionType": "LERC2D",
+ "bandNames": ["Band_1"],
+ "allowCopy": true,
+ "allowAnalysis": true,
+ "defaultVariable": "",
+ "bandCount": 1,
+ "noDataValue": -999,
+ "noDataValues": [-999],
+ "pixelType": "F64",
+ "minPixelSize": 0,
+ "maxPixelSize": 0,
+ "copyrightText": "Some copyright",
+ "serviceDataType": "esriImageServiceDataTypeScientific",
+ "serviceSourceType": "esriImageServiceSourceTypeDataset",
+ "minValues": [0],
+ "maxValues": [8972.0625],
+ "meanValues": [2224.8882386419177],
+ "stdvValues": [2508.1968623077223],
+ "objectIdField": "",
+ "fields": [],
+ "capabilities": "Mensuration,Image,Metadata",
+ "defaultMosaicMethod": "Center",
+ "allowedMosaicMethods": "",
+ "sortField": "",
+ "sortValue": null,
+ "sortAscending": true,
+ "mosaicOperator": "First",
+ "defaultCompressionQuality": 75,
+ "defaultResamplingMethod": "Bilinear",
+ "maxImageHeight": 4100,
+ "maxImageWidth": 15000,
+ "allowRasterFunction": true,
+ "rasterFunctionInfos": [
+ {
+ "name": "None",
+ "description": "",
+ "help": ""
+ }
+ ],
+ "rasterTypeInfos": [
+ {
+ "name": "Raster Dataset",
+ "description": "Supports all ArcGIS Raster Datasets",
+ "help": ""
+ }
+ ],
+ "mensurationCapabilities": "Basic",
+ "hasHistograms": true,
+ "hasColormap": false,
+ "hasRasterAttributeTable": false,
+ "minScale": 0,
+ "maxScale": 0,
+ "exportTilesAllowed": false,
+ "supportsStatistics": false,
+ "supportsAdvancedQueries": false,
+ "editFieldsInfo": null,
+ "ownershipBasedAccessControlForRasters": null,
+ "allowComputeTiePoints": false,
+ "useStandardizedQueries": true,
+ "advancedQueryCapabilities": {
+ "useStandardizedQueries": true,
+ "supportsStatistics": false,
+ "supportsOrderBy": false,
+ "supportsDistinct": false,
+ "supportsPagination": false
+ },
+ "spatialReference": {
+ "wkid": 4326,
+ "latestWkid": 4326
+ }
+}
diff --git a/wwwroot/test/ArcGisImageServer/time/legend.json b/wwwroot/test/ArcGisImageServer/time/legend.json
new file mode 100644
index 00000000000..ed6654e0c05
--- /dev/null
+++ b/wwwroot/test/ArcGisImageServer/time/legend.json
@@ -0,0 +1,38 @@
+{
+ "layers": [
+ {
+ "layerId": 0,
+ "layerName": "Some time layer",
+ "layerType": "Raster Layer",
+ "minScale": 0,
+ "maxScale": 0,
+ "legendType": "Stretched",
+ "legend": [
+ {
+ "label": "High : Some Value",
+ "url": "9632f29a708d14f7ffa6950657169300",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAeElEQVQ4ja3RsQ3CQBQE0TlYhAiQ8B04owD334q7gAACJ0jno4n5BTxp/paxXAfS7eunhHqwPADCfJTBm+oRHnbyZCc31SPMJxls+sr2KM1OrnLydvaSLzvk3asGPgvkxeSBQL7cNRAgG14yQH42OMQfApTeuwr+AYLYEoMMYRRCAAAAAElFTkSuQmCC",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "",
+ "url": "993dab15d066b40b3591f48bd77d5666",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAh0lEQVQ4jbXTsQ3CQBSD4d/KEx26VCg1M7EBW2UDVkpBdZBQIEikSBR3gSWMB/ga27qU/ospJ50VA0+XB0DcaLzgnb0XHDl4wczRCopSbC1XSZEeLg7oINLoBicjCET7MoNpMYPt6nzKRiy5GkER89XoAfHJZnD33oxcQ6TZ6PGHHapWZ8vwA8yIImKpipDXAAAAAElFTkSuQmCC",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ },
+ {
+ "label": "Low : Some Value",
+ "url": "92a46f91e372e90744ce1a7d03335211",
+ "imageData": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAAAAAAAAAHqZRakAAAAIUlEQVQ4jWP8+/cvAzUBE1VNGzVw1MBRA0cNHDVwCBkIAEMfAx/78kANAAAAAElFTkSuQmCC",
+ "contentType": "image/png",
+ "height": 20,
+ "width": 20
+ }
+ ]
+ }
+ ]
+}
diff --git a/wwwroot/test/cogs/32756.tif b/wwwroot/test/cogs/32756.tif
new file mode 100644
index 00000000000..776e0d7429f
Binary files /dev/null and b/wwwroot/test/cogs/32756.tif differ
diff --git a/wwwroot/test/cogs/4326.tif b/wwwroot/test/cogs/4326.tif
new file mode 100644
index 00000000000..c3f9bc9c3af
Binary files /dev/null and b/wwwroot/test/cogs/4326.tif differ
diff --git a/yarn.lock b/yarn.lock
index 1a1c86baef3..a5f755636ef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1640,17 +1640,10 @@
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.3.tgz#87d990bf504d14ad6b16766979d04e943c046dac"
integrity sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==
-"@types/d3-array@^2.0.0":
- version "2.12.3"
- resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-2.12.3.tgz#8d16d51fb04ad5a5a8ebe14eb8263a579f1efdd1"
- integrity sha512-hN879HLPTVqZV3FQEXy7ptt083UXwguNbnxdTGzVW4y4KjX5uyNKljrQixZcSJfLyFirbpUokxpXtvR+N5+KIg==
-
-"@types/d3-axis@^1.0.12":
- version "1.0.16"
- resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-1.0.16.tgz#93d7a28795c2f8b0e2fd550fcc4d29b7f174e693"
- integrity sha512-p7085weOmo4W+DzlRRVC/7OI/jugaKbVa6WMQGCQscaMylcbuaVEGk7abJLNyGVFLeCBNrHTdDiqRGnzvL0nXQ==
- dependencies:
- "@types/d3-selection" "^1"
+"@types/d3-array@^3.2.1":
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5"
+ integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==
"@types/d3-color@*":
version "3.1.3"
@@ -1696,10 +1689,10 @@
resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.9.tgz#73526b150d14cd96e701597cbf346cfd1fd4a58c"
integrity sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==
-"@types/d3-scale-chromatic@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-2.0.1.tgz#495cbbae7273e0d0ff564cdc19aa6d2b9928da83"
- integrity sha512-3EuZlbPu+pvclZcb1DhlymTWT2W+lYsRKBjvkH2ojDbCWDYavifqu1vYX9WGzlPgCgcS4Alhk1+zapXbGEGylQ==
+"@types/d3-scale-chromatic@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz#fc0db9c10e789c351f4c42d96f31f2e4df8f5644"
+ integrity sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==
"@types/d3-scale@4.0.2":
version "4.0.2"
@@ -1708,10 +1701,10 @@
dependencies:
"@types/d3-time" "*"
-"@types/d3-selection@^1", "@types/d3-selection@^1.4.1":
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-1.4.3.tgz#36928bbe64eb8e0bbcbaa01fb05c21ff6c71fa93"
- integrity sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==
+"@types/d3-selection@*", "@types/d3-selection@^3.0.10":
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe"
+ integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==
"@types/d3-shape@^1.3.1":
version "1.3.8"
@@ -1735,12 +1728,12 @@
resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
-"@types/d3-transition@^1.1.4":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-1.3.2.tgz#ed59beca7b4d679cfa52f88a6a50e5bbeb7e0a3c"
- integrity sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==
+"@types/d3-transition@^3.0.8":
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f"
+ integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==
dependencies:
- "@types/d3-selection" "^1"
+ "@types/d3-selection" "*"
"@types/dateformat@^3.0.1":
version "3.0.1"
@@ -1807,11 +1800,6 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
-"@types/json5@^0.0.30":
- version "0.0.30"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818"
- integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==
-
"@types/leaflet@^1.7.10":
version "1.7.10"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.10.tgz#092f97af29bb870b7d1ed72d516d4b3dde66a6c8"
@@ -1819,6 +1807,16 @@
dependencies:
"@types/geojson" "*"
+"@types/linkify-it@^3.0.5":
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8"
+ integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==
+
+"@types/linkify-it@^5":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76"
+ integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==
+
"@types/lodash-es@^4.17.3":
version "4.17.5"
resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.5.tgz#1c3fdd16849d84aea43890b1c60da379fb501353"
@@ -1831,11 +1829,24 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8"
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
+"@types/markdown-it@^14.0.1":
+ version "14.1.2"
+ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-14.1.2.tgz#57f2532a0800067d9b934f3521429a2e8bfb4c61"
+ integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==
+ dependencies:
+ "@types/linkify-it" "^5"
+ "@types/mdurl" "^2"
+
"@types/math-expression-evaluator@^1.2.0":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@types/math-expression-evaluator/-/math-expression-evaluator-1.2.2.tgz#05970d669d8c27c43f97d1557fa2a67e79698100"
integrity sha512-eHy3f0C2mfFdHbK2zoKRXaM830dm2pSTUBWZ3aJCWxFsOxErWsXNPziFLliqBddGYreCM4Nyl1IZwFCt0jwRNg==
+"@types/mdurl@^2":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd"
+ integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==
+
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
@@ -1881,6 +1892,11 @@
resolved "https://registry.yarnpkg.com/@types/pbf/-/pbf-3.0.2.tgz#8d291ad68b4b8c533e96c174a2e3e6399a59ed61"
integrity sha512-EDrLIPaPXOZqDjrkzxxbX7UlJSeQVgah3i0aA4pOSzmK9zq3BIh7/MZIQxED7slJByvKM4Gc6Hypyu2lJzh3SQ==
+"@types/proj4@^2.5.5":
+ version "2.5.5"
+ resolved "https://registry.yarnpkg.com/@types/proj4/-/proj4-2.5.5.tgz#044d53782dc75f20335577ca3af2643962a56980"
+ integrity sha512-y4tHUVVoMEOm2nxRLQ2/ET8upj/pBmoutGxFw2LZJTQWPgWXI+cbxVEUFFmIzr/bpFR83hGDOTSXX6HBeObvZA==
+
"@types/prop-types@*":
version "15.7.4"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
@@ -1891,21 +1907,6 @@
resolved "https://registry.yarnpkg.com/@types/rbush/-/rbush-3.0.0.tgz#b6887d99b159e87ae23cd14eceff34f139842aa6"
integrity sha512-W3ue/GYWXBOpkRm0VSoifrP3HV0Ni47aVJWvXyWMcbtpBy/l/K/smBRiJ+fI8f7shXRjZBiux+iJzYbh7VmcZg==
-"@types/rc-slider@^8.6.6":
- version "8.6.6"
- resolved "https://registry.yarnpkg.com/@types/rc-slider/-/rc-slider-8.6.6.tgz#961ccfd0b8c632a9d8cdcc28b54d6be4781c419f"
- integrity sha512-2Q3vwKrSm3PbgiMNwzxMkOaMtcAGi0xQ8WPeVKoabk1vNYHiVR44DMC3mr9jC2lhbxCBgGBJWF9sBhmnSDQ8Bg==
- dependencies:
- "@types/rc-tooltip" "*"
- "@types/react" "*"
-
-"@types/rc-tooltip@*":
- version "3.7.6"
- resolved "https://registry.yarnpkg.com/@types/rc-tooltip/-/rc-tooltip-3.7.6.tgz#d3833b3f3e494ab14e4a95158f9f6b321042c97a"
- integrity sha512-Otouf6HW49RSwtTa3EBdp0+BZoOQy3KDTEcVgLdZEgcYp4HB5nP6N3S6bTUkPtq3H5KmYBzEOaiq0SNMB/MY2g==
- dependencies:
- "@types/react" "*"
-
"@types/react-color@^3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.6.tgz#602fed023802b2424e7cd6ff3594ccd3d5055f9a"
@@ -2451,6 +2452,11 @@
"@webassemblyjs/wast-parser" "1.9.0"
"@xtuc/long" "4.2.2"
+"@xmldom/xmldom@^0.8.10":
+ version "0.8.10"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
+ integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
+
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -2715,6 +2721,11 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -2924,11 +2935,6 @@ async@~0.2.10:
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
-async@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/async/-/async-1.2.1.tgz#a4816a17cd5ff516dfa2c7698a453369b9790de0"
- integrity sha1-pIFqF81f9RbfosdpikUzabl5DeA=
-
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -3637,21 +3643,6 @@ chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.4.2:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
- integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
- dependencies:
- anymatch "~3.1.2"
- braces "~3.0.2"
- glob-parent "~5.1.2"
- is-binary-path "~2.1.0"
- is-glob "~4.0.1"
- normalize-path "~3.0.0"
- readdirp "~3.6.0"
- optionalDependencies:
- fsevents "~2.3.2"
-
chokidar@^2.0.0, chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -3671,6 +3662,21 @@ chokidar@^2.0.0, chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
+chokidar@^3.4.1, chokidar@^3.4.2:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
chokidar@^3.5.1:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
@@ -3686,6 +3692,13 @@ chokidar@^3.5.1:
optionalDependencies:
fsevents "~2.3.2"
+chokidar@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41"
+ integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==
+ dependencies:
+ readdirp "^4.0.1"
+
chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
@@ -3962,11 +3975,6 @@ console-browserify@^1.1.0:
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
-console-polyfill@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/console-polyfill/-/console-polyfill-0.3.0.tgz#84900902a18c47a5eba932be75fa44d23e8af861"
- integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ==
-
constants-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
@@ -4128,7 +4136,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-create-react-class@^15.5.2:
+create-react-class@^15.5.2, create-react-class@^15.7.0:
version "15.7.0"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e"
integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==
@@ -4291,7 +4299,7 @@ custom-event@~1.0.0:
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=
-"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3":
+"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
@@ -4305,32 +4313,7 @@ d3-array@3.2.1:
dependencies:
internmap "1 - 2"
-d3-array@^1.0.0, d3-array@^1.2.0:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
- integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
-
-d3-axis@^1.0.0:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9"
- integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==
-
-d3-collection@1, d3-collection@^1.0.0:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
- integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==
-
-d3-color@1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a"
- integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==
-
-"d3-color@1 - 2":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e"
- integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==
-
-"d3-color@1 - 3", d3-color@3.1.0, d3-color@^3.0.1:
+"d3-color@1 - 3", d3-color@3.1.0, d3-color@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
@@ -4342,28 +4325,23 @@ d3-delaunay@6.0.2:
dependencies:
delaunator "5"
-d3-dispatch@1, d3-dispatch@^1.0.5:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58"
- integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==
+"d3-dispatch@1 - 3":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
+ integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
-d3-drag@1:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70"
- integrity sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==
+"d3-drag@2 - 3":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
+ integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
dependencies:
- d3-dispatch "1"
- d3-selection "1"
+ d3-dispatch "1 - 3"
+ d3-selection "3"
-d3-ease@1, d3-ease@^1.0.5:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2"
- integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==
-
-d3-format@1:
- version "1.4.5"
- resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
- integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
+"d3-ease@1 - 3", d3-ease@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
"d3-format@1 - 3", d3-format@3.1.0:
version "3.1.0"
@@ -4377,21 +4355,7 @@ d3-geo@3.1.0:
dependencies:
d3-array "2.5.0 - 3"
-d3-interpolate@1, d3-interpolate@^1.3.2:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
- integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==
- dependencies:
- d3-color "1"
-
-"d3-interpolate@1 - 2":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163"
- integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==
- dependencies:
- d3-color "1 - 2"
-
-"d3-interpolate@1.2.0 - 3", d3-interpolate@3.0.1:
+"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3.0.1, d3-interpolate@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
@@ -4403,13 +4367,18 @@ d3-path@1, d3-path@^1.0.5:
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf"
integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==
-d3-scale-chromatic@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz#c13f3af86685ff91323dc2f0ebd2dabbd72d8bab"
- integrity sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==
+d3-path@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
+ integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==
+
+d3-scale-chromatic@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314"
+ integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==
dependencies:
- d3-color "1 - 2"
- d3-interpolate "1 - 2"
+ d3-color "1 - 3"
+ d3-interpolate "1 - 3"
d3-scale@4.0.2:
version "4.0.2"
@@ -4422,36 +4391,24 @@ d3-scale@4.0.2:
d3-time "2.1.1 - 3"
d3-time-format "2 - 4"
-d3-scale@^2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
- integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==
- dependencies:
- d3-array "^1.2.0"
- d3-collection "1"
- d3-format "1"
- d3-interpolate "1"
- d3-time "1"
- d3-time-format "2"
-
-d3-selection@1, d3-selection@^1.0.0, d3-selection@^1.1.0:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c"
- integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==
+"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
+ integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
-d3-shape@^1.0.0, d3-shape@^1.0.6, d3-shape@^1.2.0:
+d3-shape@^1.0.6, d3-shape@^1.2.0:
version "1.3.7"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==
dependencies:
d3-path "1"
-d3-time-format@2:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850"
- integrity sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==
+d3-shape@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
+ integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==
dependencies:
- d3-time "1"
+ d3-path "^3.1.0"
"d3-time-format@2 - 4", d3-time-format@4.1.0:
version "4.1.0"
@@ -4460,11 +4417,6 @@ d3-time-format@2:
dependencies:
d3-time "1 - 3"
-d3-time@1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1"
- integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==
-
"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7"
@@ -4472,33 +4424,32 @@ d3-time@1:
dependencies:
d3-array "2 - 3"
-d3-timer@1:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5"
- integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==
+"d3-timer@1 - 3":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
-d3-transition@1, d3-transition@^1.0.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398"
- integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==
- dependencies:
- d3-color "1"
- d3-dispatch "1"
- d3-ease "1"
- d3-interpolate "1"
- d3-selection "^1.1.0"
- d3-timer "1"
-
-d3-zoom@^1.8.3:
- version "1.8.3"
- resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a"
- integrity sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==
- dependencies:
- d3-dispatch "1"
- d3-drag "1"
- d3-interpolate "1"
- d3-selection "1"
- d3-transition "1"
+"d3-transition@2 - 3", d3-transition@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
+ integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
+ dependencies:
+ d3-color "1 - 3"
+ d3-dispatch "1 - 3"
+ d3-ease "1 - 3"
+ d3-interpolate "1 - 3"
+ d3-timer "1 - 3"
+
+d3-zoom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
+ integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "2 - 3"
+ d3-transition "2 - 3"
d@1, d@^1.0.1:
version "1.0.1"
@@ -4560,13 +4511,6 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
dependencies:
ms "^2.1.1"
-decache@^3.0.5:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/decache/-/decache-3.1.0.tgz#4f5036fbd6581fcc97237ac3954a244b9536c2da"
- integrity sha1-T1A2+9ZYH8yXI3rDlUokS5U2wto=
- dependencies:
- find "^0.2.4"
-
decamelize@^1.1.1, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -5073,10 +5017,10 @@ entities@^3.0.1:
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
-entities@~2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
- integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
+entities@^4.4.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
errno@^0.1.3:
version "0.1.8"
@@ -5092,13 +5036,6 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-error-stack-parser@^2.0.4:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8"
- integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==
- dependencies:
- stackframe "^1.1.1"
-
es-abstract@^1.19.0, es-abstract@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
@@ -5606,12 +5543,12 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
-fast-xml-parser@^3.14.0:
- version "3.21.1"
- resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz#152a1d51d445380f7046b304672dd55d15c9e736"
- integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==
+fast-xml-parser@^4.3.6:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz#341cc98de71e9ba9e651a67f41f1752d1441a501"
+ integrity sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==
dependencies:
- strnum "^1.0.4"
+ strnum "^1.0.5"
fastq@^1.6.0:
version "1.13.0"
@@ -5757,13 +5694,6 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
-find@^0.2.4:
- version "0.2.9"
- resolved "https://registry.yarnpkg.com/find/-/find-0.2.9.tgz#4b73f1ff9e56ad91b76e716407fe5ffe6554bb8c"
- integrity sha1-S3Px/55WrZG3bnFkB/5f/mVUu4w=
- dependencies:
- traverse-chain "~0.1.0"
-
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@@ -7293,11 +7223,6 @@ is-wsl@^2.1.0, is-wsl@^2.2.0:
dependencies:
is-docker "^2.0.0"
-is_js@^0.9.0:
- version "0.9.0"
- resolved "https://registry.yarnpkg.com/is_js/-/is_js-0.9.0.tgz#0ab94540502ba7afa24c856aa985561669e9c52d"
- integrity sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=
-
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -7579,7 +7504,7 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
+json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
@@ -7902,19 +7827,12 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-linkify-it@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
- integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
- dependencies:
- uc.micro "^1.0.1"
-
-linkify-it@^3.0.1:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"
- integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==
+linkify-it@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421"
+ integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
dependencies:
- uc.micro "^1.0.1"
+ uc.micro "^2.0.0"
load-json-file@^1.0.0:
version "1.1.0"
@@ -8083,11 +8001,6 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
-lru-cache@~2.2.1:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
- integrity sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=
-
make-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@@ -8132,16 +8045,17 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
-markdown-it@^11.0.0:
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-11.0.1.tgz#b54f15ec2a2193efa66dda1eb4173baea08993d6"
- integrity sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==
+markdown-it@^14.1.0:
+ version "14.1.0"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45"
+ integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==
dependencies:
- argparse "^1.0.7"
- entities "~2.0.0"
- linkify-it "^3.0.1"
- mdurl "^1.0.1"
- uc.micro "^1.0.5"
+ argparse "^2.0.1"
+ entities "^4.4.0"
+ linkify-it "^5.0.0"
+ mdurl "^2.0.0"
+ punycode.js "^2.3.1"
+ uc.micro "^2.1.0"
matchdep@^2.0.0:
version "2.0.0"
@@ -8179,10 +8093,10 @@ md5.js@^1.3.4:
inherits "^2.0.1"
safe-buffer "^5.1.2"
-mdurl@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
- integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
+mdurl@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0"
+ integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
media-typer@0.3.0:
version "0.3.0"
@@ -9632,6 +9546,11 @@ pumpify@^1.3.5:
inherits "^2.0.3"
pump "^2.0.0"
+punycode.js@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7"
+ integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
+
punycode@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
@@ -10073,6 +9992,11 @@ readdirp@^2.2.1:
micromatch "^3.1.10"
readable-stream "^2.0.2"
+readdirp@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.1.tgz#b2fe35f8dca63183cd3b86883ecc8f720ea96ae6"
+ integrity sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==
+
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -10230,13 +10154,6 @@ replace-homedir@^1.0.0:
is-absolute "^1.0.0"
remove-trailing-separator "^1.1.0"
-request-ip@~2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-2.0.2.tgz#deeae6d4af21768497db8cd05fa37143f8f1257e"
- integrity sha1-3urm1K8hdoSX24zQX6NxQ/jxJX4=
- dependencies:
- is_js "^0.9.0"
-
request-promise-core@1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
@@ -10456,22 +10373,6 @@ robust-predicates@^3.0.2:
resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771"
integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==
-rollbar@^2.24.0:
- version "2.24.0"
- resolved "https://registry.yarnpkg.com/rollbar/-/rollbar-2.24.0.tgz#3e0986ee6600d06d3abd4d85f471bcbc11fafc99"
- integrity sha512-cjAGDeTOUH5Bc4qzXlrp2D3eTO51adMWMxzOrr079t/nZidrO8ISBFM8SnazJVv5fOjIX5VbB/4a+gwbn9l4rw==
- dependencies:
- async "~1.2.1"
- console-polyfill "0.3.0"
- error-stack-parser "^2.0.4"
- json-stringify-safe "~5.0.0"
- lru-cache "~2.2.1"
- request-ip "~2.0.1"
- source-map "^0.5.7"
- uuid "3.0.x"
- optionalDependencies:
- decache "^3.0.5"
-
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -10512,12 +10413,12 @@ sass-loader@^10:
schema-utils "^3.0.0"
semver "^7.3.2"
-sass@^1.66.1:
- version "1.69.7"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.7.tgz#6e7e1c8f51e8162faec3e9619babc7da780af3b7"
- integrity sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==
+sass@^1.79.1:
+ version "1.79.4"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.79.4.tgz#f9c45af35fbeb53d2c386850ec842098d9935267"
+ integrity sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==
dependencies:
- chokidar ">=3.0.0 <4.0.0"
+ chokidar "^4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
@@ -11044,11 +10945,6 @@ stack-trace@0.0.10:
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
-stackframe@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303"
- integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==
-
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@@ -11267,7 +11163,7 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-strnum@^1.0.4:
+strnum@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
@@ -11460,10 +11356,10 @@ terriajs-cesium-widgets@5.0.0:
nosleep.js "^0.12.0"
terriajs-cesium "^8.0.0"
-terriajs-cesium@8.0.0, terriajs-cesium@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/terriajs-cesium/-/terriajs-cesium-8.0.0.tgz#7f83b5fa12014c2803f8e2513be3f1779913dd99"
- integrity sha512-YpNZh1fmBaRuyVQP1R6/0C5CfwwuVAGvJGgXSD1rSskjpynQ3MmRNi+YfqzsHxkkyUBEOtLFnzPxRYDAy/Id0w==
+terriajs-cesium@8.0.1, terriajs-cesium@^8.0.0:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/terriajs-cesium/-/terriajs-cesium-8.0.1.tgz#2f7fb10d8f2d54258022a650d19fb1afe1a3a7d7"
+ integrity sha512-99sEp1DKC2g67QwRueE+EZxbOrI9nAw+LP5AsGBtJqr6cD+20Whkx3kMDweE4tjeBMWPjDMZbsbFbILbbSqqVw==
dependencies:
"@tweenjs/tween.js" "^23.1.1"
"@zip.js/zip.js" "^2.7.34"
@@ -11549,13 +11445,13 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-thredds-catalog-crawler@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/thredds-catalog-crawler/-/thredds-catalog-crawler-0.0.6.tgz#5c7bf00dfa1846f35e3b5835f81b70639966487f"
- integrity sha512-xyxSTSTOnx3Fem+k8mgIOJYI6LXJvBK4IvrNDuNEluzvgubdEJ5x/Bk3GGrcXXy8HlD09An4Ha/nCDT2wdXSiA==
+thredds-catalog-crawler@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/thredds-catalog-crawler/-/thredds-catalog-crawler-0.0.7.tgz#67b06d5b279f8ef798cd20cb9443b05cda2388a9"
+ integrity sha512-B9TmJ3M4nGKQ8vqoFnWaLE7le8KP8Fygne4jwybF2h8fCPftbe8BK49X3Nru380voMfl4JdBSjI3zNRdkckPyQ==
dependencies:
- fast-xml-parser "^3.14.0"
- xmldom "^0.5.0"
+ "@xmldom/xmldom" "^0.8.10"
+ fast-xml-parser "^4.3.6"
through2-filter@^3.0.0:
version "3.0.0"
@@ -11737,11 +11633,6 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
-traverse-chain@~0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
- integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=
-
traverse@^0.6.6:
version "0.6.6"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
@@ -11871,10 +11762,10 @@ ua-parser-js@^0.7.30:
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832"
integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
-uc.micro@^1.0.1, uc.micro@^1.0.5:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
- integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
+uc.micro@^2.0.0, uc.micro@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee"
+ integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
unbox-primitive@^1.0.1:
version "1.0.1"
@@ -12117,11 +12008,6 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-uuid@3.0.x:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
- integrity sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=
-
uuid@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c"
@@ -12624,11 +12510,6 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
-xmldom@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e"
- integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==
-
xmldom@~0.1.19:
version "0.1.31"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"