UNPKG

terriajs

Version:

Geospatial data visualization platform.

265 lines (226 loc) 8.03 kB
import { action, runInAction } from "mobx"; import filterOutUndefined from "../../../Core/filterOutUndefined"; import isDefined from "../../../Core/isDefined"; import loadJson from "../../../Core/loadJson"; import loadWithXhr from "../../../Core/loadWithXhr"; import CatalogFunctionJobMixin from "../../../ModelMixins/CatalogFunctionJobMixin"; import TableMixin from "../../../ModelMixins/TableMixin"; import YDYRCatalogFunctionJobTraits from "../../../Traits/TraitsClasses/YDYRCatalogFunctionJobTraits"; import CommonStrata from "../../Definition/CommonStrata"; import CreateModel from "../../Definition/CreateModel"; import CsvCatalogItem from "../CatalogItems/CsvCatalogItem"; import proxyCatalogItemUrl from "../proxyCatalogItemUrl"; import { ALGORITHMS, DATASETS } from "./YDYRCatalogFunction"; export default class YDYRCatalogFunctionJob extends CatalogFunctionJobMixin( CreateModel(YDYRCatalogFunctionJobTraits) ) { readonly typeName = "YourDataYourRegions Job"; static readonly type = "ydyr-job"; get type() { return YDYRCatalogFunctionJob.type; } @action async _invoke() { if (!isDefined(this.parameters)) { throw "Parameters have not been set"; } if (!isDefined(this.parameters["apiUrl"])) { throw "The apiUrl parameter must be defined."; } if (!isDefined(this.parameters!["Input Layer"])) { throw "The input layer must be defined"; } const tableCatalogItem = this.terria.workbench.items .filter(TableMixin.isMixedInto) .filter((item) => item.uniqueId === this.parameters!["Input Layer"])[0]; if (!isDefined(tableCatalogItem)) { throw `Layer ${ this.parameters!["Input Layer"] } is not a valid layer in the workbench`; } if ( !isDefined(this.parameters["Region Column"]) || !isDefined(this.parameters["Data Column"]) || !isDefined(this.parameters["Output Geography"]) ) { throw `The region column, data column and output geography must be defined`; } const regionColumnName = this.parameters["Region Column"] as string; const dataColumnName = this.parameters["Data Column"] as string; const outputGeographyName = this.parameters["Output Geography"] as string; const regionColumn = tableCatalogItem?.findColumnByName(regionColumnName); const dataColumn = tableCatalogItem?.findColumnByName(dataColumnName); this.setTrait( CommonStrata.user, "name", `YDYR ${tableCatalogItem.name}: ${dataColumnName}` ); const jobDetails = this.addObject( CommonStrata.user, "shortReportSections", "Job Details" ); jobDetails?.setTrait( CommonStrata.user, "content", `${dataColumnName}: "${ DATASETS.find( (d) => d.geographyName === regionColumn?.regionType?.regionType )?.title }" to "${outputGeographyName}"` ); const data = { ids: regionColumn?.values, values: dataColumn?.valuesAsNumbers.values }; if (!data.ids?.length || !data.values?.length) { throw `The column selected has no valid data values`; } // Remove rows with null values const invalidRows: number[] = filterOutUndefined( data.values.map((val, idx) => (val === null ? idx : undefined)) ); data.ids = data.ids.filter((id, idx) => !invalidRows.includes(idx)); data.values = data.values.filter( (value, idx) => !invalidRows.includes(idx) ); const params = { data, data_column: dataColumnName, geom_column: regionColumnName, side_data: DATASETS.find((d) => d.title === outputGeographyName) ?.sideData, dst_geom: DATASETS.find((d) => d.title === outputGeographyName) ?.geographyName, src_geom: tableCatalogItem?.activeTableStyle.regionColumn?.regionType?.regionType, averaged_counts: false, algorithms: ALGORITHMS.filter((alg) => this.parameters![alg[0]]).map( (alg) => alg[0] ) }; const jobId = await loadWithXhr({ url: proxyCatalogItemUrl( this, `${this.parameters["apiUrl"]}disaggregate.json` ), method: "POST", data: JSON.stringify(params), headers: { "Content-Type": "application/json" }, responseType: "json" }); if (typeof jobId !== "string") { // TODO: improve error messaging // This is from previous YDYR web-app // switch(createJobReponse.status) { // case 202: // createJobReponse.response // break // case 500: // break // default: // break // } // if(r.status === 202) { // // then the request was accepted // r.json().then(j => poller(j)); // } else if(r.status === 500) { // // server error // r.json().then(e => error({ // title: (e && e.title) || 'Server Error', // detail: 'Job failed to submit' + // ((e && e.detail) ? (': ' + e.detail) : '')})); // } else { // const subber = s => { // if(s.includes('is not valid under any of the given schemas')) { // return 'invalid JSON data'; // } // return s.length < 100 ? s : (s.substring(0, 100) + '...'); // } // r.json() // .then(e => error({ // title: (e && e.title) || 'Server Error', // detail: 'Unexpected status (' + r.status.toString() + ') ' + // 'when submitting job' + // ((e && e.detail) ? (': ' + subber(e.detail)) : '')})) // .catch(e => error({ // title: (e && e.title) || 'Error parsing JSON response', // detail: `Received ${r.status} response code and failed to parse response as JSON` // })); // } throw `The YDYR server didn't provide a valid job id.`; } this.setTrait(CommonStrata.user, "jobId", jobId); return false; } async pollForResults() { if (!isDefined(this.jobId)) { console.log("NO JOB ID"); return true; } if (!isDefined(this.parameters!["apiUrl"])) { console.log("apiUrl parameter is not defined"); return true; } const status = await loadJson( proxyCatalogItemUrl( this, `${this.parameters!["apiUrl"]}status/${this.jobId}` ), { "Cache-Control": "no-cache" } ); if (typeof status !== "string") { runInAction(() => this.setTrait(CommonStrata.user, "logs", [ ...this.logs, JSON.stringify(status) ]) ); this.setTrait(CommonStrata.user, "resultId", status.key); return true; } else { runInAction(() => this.setTrait(CommonStrata.user, "logs", [...this.logs, status]) ); return false; } } async downloadResults() { if (!isDefined(this.resultId)) { return []; } if (!isDefined(this.parameters!["apiUrl"])) { console.log("apiUrl parameter is not defined"); return []; } const csvResult = new CsvCatalogItem( `${this.uniqueId}-result`, this.terria, undefined ); let regionColumnSplit = DATASETS.find( (d) => d.title === this.parameters?.["Output Geography"] )?.geographyName.split("_"); let regionColumn = ""; if (isDefined(regionColumnSplit) && regionColumnSplit!.length === 2) { regionColumn = `${regionColumnSplit![0]}_code_${regionColumnSplit![1]}`; } runInAction(() => { csvResult.setTrait(CommonStrata.user, "name", `${this.name} Results`); csvResult.setTrait( CommonStrata.user, "url", proxyCatalogItemUrl( this, `${this.parameters!["apiUrl"]}download/${this.resultId}?format=csv` ) ); csvResult.setTrait(CommonStrata.user, "enableManualRegionMapping", true); }); return [csvResult]; } }