terriajs
Version:
Geospatial data visualization platform.
206 lines • 11.5 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { observer } from "mobx-react";
import { runInAction } from "mobx";
import PropTypes from "prop-types";
import { Component } from "react";
import { Trans, withTranslation } from "react-i18next";
import { Category, DatatabAction } from "../../../../Core/AnalyticEvents/analyticEvents";
import getDataType from "../../../../Core/getDataType";
import TimeVarying from "../../../../ModelMixins/TimeVarying";
import addUserCatalogMember from "../../../../Models/Catalog/addUserCatalogMember";
import addUserFiles from "../../../../Models/Catalog/addUserFiles";
import CatalogMemberFactory from "../../../../Models/Catalog/CatalogMemberFactory";
import createCatalogItemFromFileOrUrl from "../../../../Models/Catalog/createCatalogItemFromFileOrUrl";
import CommonStrata from "../../../../Models/Definition/CommonStrata";
import upsertModelFromJson from "../../../../Models/Definition/upsertModelFromJson";
import Icon from "../../../../Styled/Icon";
import Dropdown from "../../../Generic/Dropdown";
import Loader from "../../../Loader";
import Styles from "./add-data.scss";
import FileInput from "./FileInput";
import { parseCustomMarkdownToReactWithOptions } from "../../../Custom/parseCustomMarkdownToReact";
import loadJson from "../../../../Core/loadJson";
import TerriaError from "../../../../Core/TerriaError";
/**
* Add data panel in modal window -> My data tab
*/
let AddData = class AddData extends Component {
static propTypes = {
terria: PropTypes.object,
viewState: PropTypes.object,
resetTab: PropTypes.func,
activeTab: PropTypes.string,
// localDataTypes & remoteDataTypes specifies the file types to show in dropdowns for local and remote data uploads.
// These default to the lists defined in getDataType.ts
// Some external components use these props to customize the types shown.
localDataTypes: PropTypes.arrayOf(PropTypes.object),
remoteDataTypes: PropTypes.arrayOf(PropTypes.object),
onFileAddFinished: PropTypes.func.isRequired,
onUrlAddFinished: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
};
constructor(props) {
super(props);
const remoteDataTypes = this.props.remoteDataTypes ?? getDataType().remoteDataType;
// Automatically suffix supported extension types to localDataType names
const localDataTypes = (this.props.localDataTypes ?? getDataType().localDataType).map((dataType) => {
const extensions = dataType.extensions?.length
? ` (${buildExtensionsList(dataType.extensions)})`
: "";
return { ...dataType, name: `${dataType.name}${extensions}` };
});
this.state = {
remoteDataTypes,
localDataTypes,
localDataType: localDataTypes[0],
remoteUrl: "", // By default there's no remote url
isLoading: false
};
}
selectLocalOption(option) {
this.setState({
localDataType: option
});
}
selectRemoteOption(option) {
runInAction(() => {
this.props.viewState.remoteDataType = option;
});
}
handleUploadFile(e) {
this.setState({
isLoading: true
});
addUserFiles(e.target.files, this.props.terria, this.props.viewState, this.state.localDataType).then((addedCatalogItems) => {
if (addedCatalogItems && addedCatalogItems.length > 0) {
this.props.onFileAddFinished(addedCatalogItems);
}
this.setState({
isLoading: false
});
// reset active tab when file handling is done
this.props.resetTab();
});
}
async handleUrl(e) {
const url = this.state.remoteUrl;
e.preventDefault();
this.props.terria.analytics?.logEvent(Category.dataTab, DatatabAction.addDataUrl, url);
this.setState({
isLoading: true
});
let promise;
if (!this.props.viewState.remoteDataType ||
this.props.viewState.remoteDataType.value === "auto") {
promise = createCatalogItemFromFileOrUrl(this.props.terria, this.state.remoteUrl, this.props.viewState.remoteDataType?.value);
}
else if (this.props.viewState.remoteDataType.value === "json") {
promise = loadJson(this.state.remoteUrl)
.then((data) => {
if (data.error) {
return Promise.reject(data.error);
}
this.props.terria.catalog.group
.addMembersFromJson(CommonStrata.user, data.catalog)
.raiseError(this.props.terria, "Failed to load catalog from file");
})
.then(() => {
this.props.onUrlAddFinished();
})
.catch((error) => TerriaError.from(error).raiseError(this.props.terria, `An error occurred trying to add data from URL: ${this.state.remoteUrl}`))
.finally(() => {
this.setState({
isLoading: false
});
});
}
else {
try {
const newItem = upsertModelFromJson(CatalogMemberFactory, this.props.terria, "", CommonStrata.defaults, { type: this.props.viewState.remoteDataType.value, name: url }, {}).throwIfUndefined({
message: `An error occurred trying to add data from URL: ${url}`
});
newItem.setTrait(CommonStrata.user, "url", url);
promise = newItem.loadMetadata().then((result) => {
if (result.error) {
return Promise.reject(result.error);
}
return Promise.resolve(newItem);
});
}
catch (e) {
promise = Promise.reject(e);
}
}
addUserCatalogMember(this.props.terria, promise).then((addedItem) => {
if (addedItem) {
this.props.onFileAddFinished([addedItem]);
if (TimeVarying.is(addedItem)) {
this.props.terria.timelineStack.addToTop(addedItem);
}
}
// FIXME: Setting state here might result in a react warning if the
// component unmounts before the promise finishes
this.setState({
isLoading: false
});
this.props.resetTab();
});
}
onRemoteUrlChange(event) {
this.setState({
remoteUrl: event.target.value
});
}
renderPanels() {
const { t } = this.props;
const dropdownTheme = {
dropdown: Styles.dropdown,
list: Styles.dropdownList,
isOpen: Styles.dropdownListIsOpen,
icon: _jsx(Icon, { glyph: Icon.GLYPHS.opened })
};
const dataTypes = this.state.localDataTypes.reduce(function (result, currentDataType) {
if (currentDataType.extensions) {
return result.concat(currentDataType.extensions.map((extension) => "." + extension));
}
else {
return result;
}
}, []);
const remoteDataType = this.props.viewState.remoteDataType ?? this.state.remoteDataTypes[0];
return (_jsxs("div", { className: Styles.tabPanels, children: [this.props.activeTab === "local" && (_jsxs(_Fragment, { children: [_jsx("div", { className: Styles.tabHeading, children: t("addData.localAdd") }), _jsxs("section", { className: Styles.tabPanel, children: [_jsx("label", { className: Styles.label, children: _jsxs(Trans, { i18nKey: "addData.localFileType", children: [_jsx("strong", { children: "Step 1:" }), " Select file type"] }) }), _jsx(Dropdown, { options: this.state.localDataTypes, selected: this.state.localDataType, selectOption: this.selectLocalOption.bind(this), matchWidth: true, theme: dropdownTheme }), this.state.localDataType?.description
? parseCustomMarkdownToReactWithOptions(this.state.localDataType?.description)
: null, _jsx("label", { className: Styles.label, children: _jsxs(Trans, { i18nKey: "addData.localFile", children: [_jsx("strong", { children: "Step 2:" }), " Select file"] }) }), _jsx(FileInput, { accept: dataTypes.join(","), onChange: this.handleUploadFile.bind(this) }), this.state.isLoading && _jsx(Loader, {})] })] })), this.props.activeTab === "web" && (_jsxs(_Fragment, { children: [_jsx("div", { className: Styles.tabHeading, children: t("addData.webAdd") }), _jsxs("section", { className: Styles.tabPanel, children: [_jsx("label", { className: Styles.label, children: _jsxs(Trans, { i18nKey: "addData.webFileType", children: [_jsx("strong", { children: "Step 1:" }), " Select file or web service type"] }) }), _jsx(Dropdown, { options: this.state.remoteDataTypes, selected: remoteDataType, selectOption: this.selectRemoteOption.bind(this), matchWidth: true, theme: dropdownTheme }), remoteDataType?.description
? parseCustomMarkdownToReactWithOptions(remoteDataType?.description)
: null, remoteDataType?.customComponent
? this.renderCustomComponent(remoteDataType?.customComponent)
: this.renderDefaultForWebDataType(t)] })] }))] }));
}
renderCustomComponent(CustomComponent) {
return _jsx(CustomComponent, {});
}
renderDefaultForWebDataType(t) {
return (_jsxs(_Fragment, { children: [_jsx("label", { className: Styles.label, children: _jsxs(Trans, { i18nKey: "addData.webFile", children: [_jsx("strong", { children: "Step 2:" }), " Enter the URL of the data file or web service"] }) }), _jsxs("form", { className: Styles.urlInput, children: [_jsx("input", { value: this.state.remoteUrl, onChange: this.onRemoteUrlChange.bind(this), className: Styles.urlInputTextBox, type: "text", placeholder: "e.g. http://data.gov.au/geoserver/wms" }), _jsx("button", { disabled: this.state.remoteUrl.length === 0, type: "submit", onClick: this.handleUrl.bind(this), className: Styles.urlInputBtn, children: t("addData.urlInputBtn") }), this.state.isLoading && _jsx(Loader, {})] })] }));
}
render() {
return _jsx("div", { className: Styles.inner, children: this.renderPanels() });
}
};
AddData = __decorate([
observer
], AddData);
/**
* @param extensions - string[]
* @returns Comma separated string of extensions
*/
function buildExtensionsList(extensions) {
return extensions.map((ext) => `.${ext}`).join(", ");
}
export default withTranslation()(AddData);
//# sourceMappingURL=AddData.js.map