diff --git a/API/Backend/Datasets/routes/datasets.js b/API/Backend/Datasets/routes/datasets.js
index fd5221d0..436c73c1 100644
--- a/API/Backend/Datasets/routes/datasets.js
+++ b/API/Backend/Datasets/routes/datasets.js
@@ -10,6 +10,7 @@ const inspect = require("util").inspect;
const { sequelize } = require("../../../connection");
+const Utils = require("../../../utils.js");
const logger = require("../../../logger");
const datasets = require("../models/datasets");
const csvtojson = require("csvtojson");
@@ -88,10 +89,63 @@ router.post("/entries", function (req, res, next) {
for (let i = 0; i < sets.length; i++) {
entries.push({ name: sets[i].name, updated: sets[i].updatedAt });
}
- res.send({
- status: "success",
- body: { entries: entries },
- });
+ // For each entry, list all occurrences in latest configuration objects
+ sequelize
+ .query(
+ `
+ SELECT t1.*
+ FROM configs AS t1
+ INNER JOIN (
+ SELECT mission, MAX(version) AS max_version
+ FROM configs
+ GROUP BY mission
+ ) AS t2
+ ON t1.mission = t2.mission AND t1.version = t2.max_version ORDER BY mission ASC;
+ `
+ )
+ .then(([results]) => {
+ // Populate occurrences
+ results.forEach((m) => {
+ Utils.traverseLayers(m.config.layers, (layer, path) => {
+ entries.forEach((entry) => {
+ entry.occurrences = entry.occurrences || {};
+ entry.occurrences[m.mission] =
+ entry.occurrences[m.mission] || [];
+ if (layer?.variables?.datasetLinks?.length != null) {
+ layer.variables.datasetLinks.forEach((d) => {
+ if (d.dataset === entry.name) {
+ entry.occurrences[m.mission].push({
+ name: layer.name,
+ uuid: layer.uuid,
+ path: path,
+ });
+ }
+ });
+ }
+ });
+ });
+ });
+
+ res.send({
+ status: "success",
+ body: { entries: entries },
+ });
+ return null;
+ })
+ .catch((err) => {
+ logger(
+ "error",
+ "Failed to find missions.",
+ req.originalUrl,
+ req,
+ err
+ );
+ res.send({
+ status: "failure",
+ message: "Failed to find missions.",
+ });
+ return null;
+ });
} else {
res.send({
status: "failure",
@@ -175,6 +229,56 @@ router.post("/search", function (req, res, next) {
});
});
+/*
+ * req.query.layer
+ */
+router.get("/download", function (req, res, next) {
+ //First Find the table name
+ Datasets.findOne({ where: { name: req.query.layer } })
+ .then((result) => {
+ if (result) {
+ let table = result.dataValues.table;
+
+ sequelize
+ .query("SELECT * FROM " + table)
+ .then(([results]) => {
+ res.send({
+ status: "success",
+ body: results,
+ });
+
+ return null;
+ })
+ .catch((err) => {
+ logger(
+ "error",
+ "SQL error downloading dataset.",
+ req.originalUrl,
+ req,
+ err
+ );
+ res.send({
+ status: "failure",
+ message: "SQL error.",
+ });
+ });
+ } else {
+ res.send({
+ status: "failure",
+ message: "Layer not found.",
+ });
+ }
+
+ return null;
+ })
+ .catch((err) => {
+ logger("error", "Failure finding dataset.", req.originalUrl, req, err);
+ res.send({
+ status: "failure",
+ });
+ });
+});
+
router.post("/upload", function (req, res, next) {
// Disable timeout
req.setTimeout(0);
diff --git a/API/Backend/Geodatasets/routes/geodatasets.js b/API/Backend/Geodatasets/routes/geodatasets.js
index a57f10dc..360b640c 100644
--- a/API/Backend/Geodatasets/routes/geodatasets.js
+++ b/API/Backend/Geodatasets/routes/geodatasets.js
@@ -291,7 +291,16 @@ router.post("/entries", function (req, res, next) {
// For each entry, list all occurrences in latest configuration objects
sequelize
.query(
- "SELECT DISTINCT ON (mission) mission, version, config FROM configs ORDER BY mission ASC"
+ `
+ SELECT t1.*
+ FROM configs AS t1
+ INNER JOIN (
+ SELECT mission, MAX(version) AS max_version
+ FROM configs
+ GROUP BY mission
+ ) AS t2
+ ON t1.mission = t2.mission AND t1.version = t2.max_version ORDER BY mission ASC;
+ `
)
.then(([results]) => {
// Populate occurrences
diff --git a/configure/src/components/Map/Map.js b/configure/src/components/Map/Map.js
index 8eb8fd8b..2132053f 100644
--- a/configure/src/components/Map/Map.js
+++ b/configure/src/components/Map/Map.js
@@ -1,8 +1,6 @@
import React, { useEffect, useState } from "react";
import * as L from "leaflet";
-import clsx from "clsx";
-
import ReactJson from "react-json-view";
import { makeStyles } from "@mui/styles";
diff --git a/configure/src/components/Panel/Panel.js b/configure/src/components/Panel/Panel.js
index 56a8a867..c435df58 100644
--- a/configure/src/components/Panel/Panel.js
+++ b/configure/src/components/Panel/Panel.js
@@ -6,12 +6,7 @@ import mmgisLogo from "../../images/mmgis.png";
import clsx from "clsx";
-import {
- setConfiguration,
- setMission,
- setModal,
- setPage,
-} from "../../core/ConfigureStore";
+import { setMission, setModal, setPage } from "../../core/ConfigureStore";
import NewMissionModal from "./Modals/NewMissionModal/NewMissionModal";
@@ -222,7 +217,7 @@ export default function Panel() {
dispatch(setPage({ page: "webhooks" }));
}}
>
- WebHooks
+ Webhooks
diff --git a/configure/src/components/SaveBar/Modals/PreviewModal/PreviewModal.js b/configure/src/components/SaveBar/Modals/PreviewModal/PreviewModal.js
index 22c6e3a6..473bea70 100644
--- a/configure/src/components/SaveBar/Modals/PreviewModal/PreviewModal.js
+++ b/configure/src/components/SaveBar/Modals/PreviewModal/PreviewModal.js
@@ -1,18 +1,9 @@
-import React, { useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
-import { calls } from "../../../../core/calls";
+import { setModal } from "../../../../core/ConfigureStore";
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
-
-import Typography from "@mui/material/Typography";
-import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
-import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import IconButton from "@mui/material/IconButton";
@@ -20,11 +11,6 @@ import IconButton from "@mui/material/IconButton";
import CloseSharpIcon from "@mui/icons-material/CloseSharp";
import PreviewIcon from "@mui/icons-material/Preview";
-import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
-
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
diff --git a/configure/src/components/SaveBar/SaveBar.js b/configure/src/components/SaveBar/SaveBar.js
index dd0f426f..3af7c5ef 100644
--- a/configure/src/components/SaveBar/SaveBar.js
+++ b/configure/src/components/SaveBar/SaveBar.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
import {} from "./SaveBarSlice";
import { makeStyles } from "@mui/styles";
diff --git a/configure/src/components/Tabs/Coordinates/Coordinates.js b/configure/src/components/Tabs/Coordinates/Coordinates.js
index 1cee7ad9..6df92656 100644
--- a/configure/src/components/Tabs/Coordinates/Coordinates.js
+++ b/configure/src/components/Tabs/Coordinates/Coordinates.js
@@ -1,10 +1,8 @@
-import React, { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
+import React from "react";
+import { useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
-import { calls } from "../../../core/calls";
import Maker from "../../../core/Maker";
-import { setSnackBarText } from "../../../core/ConfigureStore";
import config from "../../../metaconfigs/tab-coordinates-config.json";
diff --git a/configure/src/components/Tabs/Home/Home.js b/configure/src/components/Tabs/Home/Home.js
index 32398123..015c3cec 100644
--- a/configure/src/components/Tabs/Home/Home.js
+++ b/configure/src/components/Tabs/Home/Home.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { setVersions } from "./HomeSlice";
import { makeStyles } from "@mui/styles";
diff --git a/configure/src/components/Tabs/Home/Modals/DeleteConfigModal/DeleteConfigModal.js b/configure/src/components/Tabs/Home/Modals/DeleteConfigModal/DeleteConfigModal.js
index 276e0b2e..2d216934 100644
--- a/configure/src/components/Tabs/Home/Modals/DeleteConfigModal/DeleteConfigModal.js
+++ b/configure/src/components/Tabs/Home/Modals/DeleteConfigModal/DeleteConfigModal.js
@@ -20,7 +20,6 @@ import IconButton from "@mui/material/IconButton";
import CloseSharpIcon from "@mui/icons-material/CloseSharp";
import ShapeLineIcon from "@mui/icons-material/ShapeLine";
-import WarningIcon from "@mui/icons-material/Warning";
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
import TextField from "@mui/material/TextField";
diff --git a/configure/src/components/Tabs/Home/Modals/UploadConfigModal/UploadConfigModal.js b/configure/src/components/Tabs/Home/Modals/UploadConfigModal/UploadConfigModal.js
index 5ba726e4..0fdcb23e 100644
--- a/configure/src/components/Tabs/Home/Modals/UploadConfigModal/UploadConfigModal.js
+++ b/configure/src/components/Tabs/Home/Modals/UploadConfigModal/UploadConfigModal.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { calls } from "../../../../../core/calls";
diff --git a/configure/src/components/Tabs/Home/Versions.js b/configure/src/components/Tabs/Home/Versions.js
index 0eb464b9..05dff816 100644
--- a/configure/src/components/Tabs/Home/Versions.js
+++ b/configure/src/components/Tabs/Home/Versions.js
@@ -1,9 +1,7 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
-import clsx from "clsx";
-
import { calls } from "../../../core/calls";
import { downloadObject } from "../../../core/utils";
import {
@@ -12,10 +10,8 @@ import {
setConfiguration,
clearLockConfig,
} from "../../../core/ConfigureStore";
-import { setVersions } from "./HomeSlice";
import PropTypes from "prop-types";
-import { alpha } from "@mui/material/styles";
import Box from "@mui/material/Box";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
@@ -25,31 +21,15 @@ import TableHead from "@mui/material/TableHead";
import TablePagination from "@mui/material/TablePagination";
import TableRow from "@mui/material/TableRow";
import TableSortLabel from "@mui/material/TableSortLabel";
-import Toolbar from "@mui/material/Toolbar";
-import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
-import Checkbox from "@mui/material/Checkbox";
import IconButton from "@mui/material/IconButton";
-import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Switch from "@mui/material/Switch";
-import DeleteIcon from "@mui/icons-material/Delete";
-import FilterListIcon from "@mui/icons-material/FilterList";
import Divider from "@mui/material/Divider";
-import Badge from "@mui/material/Badge";
import { visuallyHidden } from "@mui/utils";
-import InventoryIcon from "@mui/icons-material/Inventory";
import PreviewIcon from "@mui/icons-material/Preview";
import DownloadIcon from "@mui/icons-material/Download";
-import UploadIcon from "@mui/icons-material/Upload";
-import DriveFileRenameOutlineIcon from "@mui/icons-material/DriveFileRenameOutline";
-import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
-import AddIcon from "@mui/icons-material/Add";
-import ShapeLineIcon from "@mui/icons-material/ShapeLine";
import LowPriorityIcon from "@mui/icons-material/LowPriority";
-import ControlPointDuplicateIcon from "@mui/icons-material/ControlPointDuplicate";
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
diff --git a/configure/src/components/Tabs/Layers/Layers.js b/configure/src/components/Tabs/Layers/Layers.js
index 705bc6a9..2fbf350e 100644
--- a/configure/src/components/Tabs/Layers/Layers.js
+++ b/configure/src/components/Tabs/Layers/Layers.js
@@ -3,19 +3,13 @@ import { useSelector, useDispatch } from "react-redux";
import {} from "./LayersSlice";
import { makeStyles } from "@mui/styles";
-import { calls } from "../../../core/calls";
import { reorderArray } from "../../../core/utils";
-import {
- setSnackBarText,
- setModal,
- setConfiguration,
-} from "../../../core/ConfigureStore";
+import { setModal, setConfiguration } from "../../../core/ConfigureStore";
import LayerModal from "./Modals/LayerModal/LayerModal";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
-import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemIcon from "@mui/material/ListItemIcon";
diff --git a/configure/src/components/Tabs/Layers/Modals/LayerModal/LayerModal.js b/configure/src/components/Tabs/Layers/Modals/LayerModal/LayerModal.js
index ff0666a1..906c1894 100644
--- a/configure/src/components/Tabs/Layers/Modals/LayerModal/LayerModal.js
+++ b/configure/src/components/Tabs/Layers/Modals/LayerModal/LayerModal.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { getLayerByUUID, traverseLayers } from "../../../../../core/utils";
diff --git a/configure/src/components/Tabs/Time/Time.js b/configure/src/components/Tabs/Time/Time.js
index f00380a6..f7c73a19 100644
--- a/configure/src/components/Tabs/Time/Time.js
+++ b/configure/src/components/Tabs/Time/Time.js
@@ -1,10 +1,8 @@
-import React, { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
+import React from "react";
+import { useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
-import { calls } from "../../../core/calls";
import Maker from "../../../core/Maker";
-import { setSnackBarText } from "../../../core/ConfigureStore";
import config from "../../../metaconfigs/tab-time-config.json";
diff --git a/configure/src/components/Tabs/Tools/Modals/ToolModal/ToolModal.js b/configure/src/components/Tabs/Tools/Modals/ToolModal/ToolModal.js
index bdee5389..af767220 100644
--- a/configure/src/components/Tabs/Tools/Modals/ToolModal/ToolModal.js
+++ b/configure/src/components/Tabs/Tools/Modals/ToolModal/ToolModal.js
@@ -1,20 +1,12 @@
-import React, { useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
-import { calls } from "../../../../../core/calls";
import {
- getLayerByUUID,
- getIn,
- setIn,
getToolFromConfiguration,
updateToolInConfiguration,
} from "../../../../../core/utils";
-import {
- setModal,
- setSnackBarText,
- setConfiguration,
-} from "../../../../../core/ConfigureStore";
+import { setModal, setConfiguration } from "../../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
diff --git a/configure/src/components/Tabs/Tools/Tools.js b/configure/src/components/Tabs/Tools/Tools.js
index e3bcc285..6aa63e68 100644
--- a/configure/src/components/Tabs/Tools/Tools.js
+++ b/configure/src/components/Tabs/Tools/Tools.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import {} from "./ToolsSlice";
import { makeStyles } from "@mui/styles";
@@ -15,7 +15,6 @@ import {
import ToolModal from "./Modals/ToolModal/ToolModal";
import Grid from "@mui/material/Grid";
-import Paper from "@mui/material/Paper";
import Box from "@mui/material/Box";
const useStyles = makeStyles((theme) => ({
diff --git a/configure/src/components/Tabs/UserInterface/UserInterface.js b/configure/src/components/Tabs/UserInterface/UserInterface.js
index 80d941aa..2e403612 100644
--- a/configure/src/components/Tabs/UserInterface/UserInterface.js
+++ b/configure/src/components/Tabs/UserInterface/UserInterface.js
@@ -1,10 +1,7 @@
-import React, { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
+import React from "react";
import { makeStyles } from "@mui/styles";
-import { calls } from "../../../core/calls";
import Maker from "../../../core/Maker";
-import { setSnackBarText } from "../../../core/ConfigureStore";
import config from "../../../metaconfigs/tab-ui-config.json";
@@ -22,8 +19,6 @@ const useStyles = makeStyles((theme) => ({
export default function UserInterface() {
const c = useStyles();
- const dispatch = useDispatch();
-
return (
diff --git a/configure/src/core/Configure.js b/configure/src/core/Configure.js
index 5af56e77..153d7cf7 100644
--- a/configure/src/core/Configure.js
+++ b/configure/src/core/Configure.js
@@ -1,6 +1,6 @@
-import { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
-import clsx from "clsx";
+import { useEffect } from "react";
+import { useDispatch } from "react-redux";
+
import { makeStyles } from "@mui/styles";
import Main from "../components/Main/Main";
diff --git a/configure/src/core/ConfigureStore.js b/configure/src/core/ConfigureStore.js
index 60ec2f97..c431a9c0 100644
--- a/configure/src/core/ConfigureStore.js
+++ b/configure/src/core/ConfigureStore.js
@@ -27,6 +27,9 @@ export const ConfigureStore = createSlice({
appendGeoDataset: false,
updateGeoDataset: false,
newDataset: false,
+ layersUsedByDataset: false,
+ updateDataset: false,
+ deleteDataset: false,
uploadConfig: false,
cloneConfig: false,
deleteConfig: false,
diff --git a/configure/src/core/Maker.js b/configure/src/core/Maker.js
index 15abd1b7..09720faf 100644
--- a/configure/src/core/Maker.js
+++ b/configure/src/core/Maker.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
@@ -7,7 +7,6 @@ import "leaflet/dist/leaflet.css";
import clsx from "clsx";
import Box from "@mui/material/Box";
-import Paper from "@mui/material/Paper";
import Grid from "@mui/material/Grid";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
@@ -29,8 +28,7 @@ import Slider from "@mui/material/Slider";
import AddIcon from "@mui/icons-material/Add";
import CloseIcon from "@mui/icons-material/Close";
-import { calls } from "./calls";
-import { setConfiguration, setSnackBarText } from "./ConfigureStore";
+import { setConfiguration } from "./ConfigureStore";
import {
getIn,
setIn,
@@ -198,6 +196,9 @@ const useStyles = makeStyles((theme) => ({
json: {
border: `1px solid ${theme.palette.swatches.grey[850]}`,
boxShadow: `0px 2px 4px 0px rgba(0, 0, 0, 0.2)`,
+ "& > div:first-child": {
+ margin: "4px 8px 0px 8px",
+ },
},
slider: {
flexFlow: "column !important",
@@ -315,11 +316,20 @@ const getComponent = (
);
case "json":
let json_f = value || getIn(directConf, com.field, {});
+ try {
+ if (typeof json_f === "string") json_f = JSON.parse(json_f);
+ } catch (err) {}
return (
+
+ {com.name || ""}
+
+ {com.description || ""}
+
+
{
try {
diff --git a/configure/src/core/Websocket.js b/configure/src/core/Websocket.js
index 5fbaa8d7..848a544c 100644
--- a/configure/src/core/Websocket.js
+++ b/configure/src/core/Websocket.js
@@ -1,14 +1,10 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
import ReportIcon from "@mui/icons-material/Report";
-import {
- setSnackBarText,
- clearLockConfig,
- setLockConfig,
-} from "./ConfigureStore";
+import { clearLockConfig, setLockConfig } from "./ConfigureStore";
const vars = {
initialWebSocketRetryInterval: 20000, // 1 minute
diff --git a/configure/src/core/calls.js b/configure/src/core/calls.js
index db1e96f0..16b2dd3e 100644
--- a/configure/src/core/calls.js
+++ b/configure/src/core/calls.js
@@ -71,9 +71,13 @@ const c = {
url: "api/datasets/entries",
},
datasets_get: {
- type: "GET",
+ type: "POST",
url: "api/datasets/get",
},
+ datasets_download: {
+ type: "GET",
+ url: "api/datasets/download",
+ },
longtermtoken_get: {
type: "GET",
url: "api/longtermtoken/get",
diff --git a/configure/src/core/routes/routes.js b/configure/src/core/routes/routes.js
index a861e651..8d38a290 100644
--- a/configure/src/core/routes/routes.js
+++ b/configure/src/core/routes/routes.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import SnackBar from "../../components/SnackBar/SnackBar";
diff --git a/configure/src/pages/APITokens/APITokens.js b/configure/src/pages/APITokens/APITokens.js
index ab121576..74d6312a 100644
--- a/configure/src/pages/APITokens/APITokens.js
+++ b/configure/src/pages/APITokens/APITokens.js
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
+import { useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
import clsx from "clsx";
@@ -39,11 +39,11 @@ const useStyles = makeStyles((theme) => ({
},
top: {
display: "flex",
- borderBottom: `1px solid ${theme.palette.swatches.grey[800]}`,
paddingBottom: "10px",
+ height: "48px",
},
title: {
- margin: "40px 60px 0px 60px",
+ margin: "18px 0px 0px 60px",
paddingBottom: "5px",
fontSize: "22px",
letterSpacing: "1px",
@@ -54,13 +54,10 @@ const useStyles = makeStyles((theme) => ({
margin: "20px 60px",
},
subtitle: {
- margin: "40px 60px 0px 60px",
+ margin: "0px 60px 0px 60px !important",
+ fontSize: "13px !important",
paddingBottom: "5px",
- fontSize: "12px",
- letterSpacing: "1px",
- color: theme.palette.swatches.p[12],
- fontWeight: "bold",
- textTransform: "uppercase",
+ fontStyle: "italic",
},
subtitle2: {
fontSize: "12px !important",
@@ -77,8 +74,8 @@ const useStyles = makeStyles((theme) => ({
},
generate: { width: "100%", height: "48px" },
generated: {
- height: "48px",
- lineHeight: "48px",
+ height: "42px",
+ lineHeight: "42px",
display: "flex",
marginBottom: "20px",
border: `2px solid ${theme.palette.swatches.p[0]}`,
@@ -94,7 +91,7 @@ const useStyles = makeStyles((theme) => ({
padding: "0px 16px",
},
"& > div:nth-child(3)": {
- height: "48px",
+ height: "42px",
},
},
genTitle: {},
@@ -103,18 +100,18 @@ const useStyles = makeStyles((theme) => ({
tokenList: {},
tokenListItem: {
display: "flex",
- height: "48px",
- lineHeight: "48px",
+ height: "42px",
+ lineHeight: "42px",
width: "100%",
background: theme.palette.swatches.grey[900],
border: `1px solid ${theme.palette.swatches.grey[700]}`,
- boxShadow: `0px 1px 4px 0px rgba(0,0,0,0.3)`,
- marginBottom: "8px",
+ boxShadow: `0px 1px 3px 0px rgba(0,0,0,0.15)`,
+ marginBottom: "3px",
"& > div:nth-child(1)": {
background: theme.palette.swatches.grey[150],
color: "white",
textAlign: "center",
- width: "48px",
+ width: "42px",
},
"& > div:nth-child(2)": { flex: 1, padding: "0px 16px" },
"& > div:nth-child(3)": {
@@ -139,10 +136,28 @@ const useStyles = makeStyles((theme) => ({
},
"& > div:nth-child(5)": {
borderLeft: `1px solid ${theme.palette.swatches.grey[700]}`,
- width: "48px",
+ width: "42px",
textAlign: "center",
},
},
+ examples: {
+ margin: "20px 0px",
+ "& > ul": {
+ listStyleType: "none",
+ padding: "0px",
+ },
+ "& > ul > li > div:first-child": {
+ fontWeight: "bold",
+ padding: "10px 0px",
+ },
+ },
+ examplesTitle: {
+ fontSize: "20px",
+ color: theme.palette.swatches.grey[150],
+ borderBottom: `1px solid ${theme.palette.swatches.grey[150]}`,
+ padding: "10px 0px",
+ fontWeight: "bold",
+ },
code: {
fontFamily: "monospace",
padding: "8px",
@@ -265,22 +280,16 @@ export default function APITokens() {
API Tokens
-
+
+
+
{
"Generate an authentication token for programmatic control over the configuration and data endpoints. The generated token may be used it requests via the header: 'Authorization:Bearer ' and more information can be found at https://nasa-ammos.github.io/MMGIS/apis/configure#api-tokens"
}
-
-
-
+
-
-
+
+
-
+
{"Expire After"}
-
+
-
-
Examples
+
+
Examples
General Usage
diff --git a/configure/src/pages/Datasets/Datasets.js b/configure/src/pages/Datasets/Datasets.js
index 5894c1d0..19394173 100644
--- a/configure/src/pages/Datasets/Datasets.js
+++ b/configure/src/pages/Datasets/Datasets.js
@@ -1,9 +1,7 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
-import clsx from "clsx";
-
import { calls } from "../../core/calls";
import { downloadObject } from "../../core/utils";
import {
@@ -13,7 +11,6 @@ import {
} from "../../core/ConfigureStore";
import PropTypes from "prop-types";
-import { alpha } from "@mui/material/styles";
import Box from "@mui/material/Box";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
@@ -26,29 +23,24 @@ import TableSortLabel from "@mui/material/TableSortLabel";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
-import Checkbox from "@mui/material/Checkbox";
import IconButton from "@mui/material/IconButton";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Switch from "@mui/material/Switch";
-import DeleteIcon from "@mui/icons-material/Delete";
-import FilterListIcon from "@mui/icons-material/FilterList";
import Divider from "@mui/material/Divider";
import Badge from "@mui/material/Badge";
import { visuallyHidden } from "@mui/utils";
import InventoryIcon from "@mui/icons-material/Inventory";
-import PreviewIcon from "@mui/icons-material/Preview";
import DownloadIcon from "@mui/icons-material/Download";
import UploadIcon from "@mui/icons-material/Upload";
-import DriveFileRenameOutlineIcon from "@mui/icons-material/DriveFileRenameOutline";
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
import AddIcon from "@mui/icons-material/Add";
-import ControlPointDuplicateIcon from "@mui/icons-material/ControlPointDuplicate";
import TextSnippetIcon from "@mui/icons-material/TextSnippet";
import NewDatasetModal from "./Modals/NewDatasetModal/NewDatasetModal";
+import LayersUsedByModal from "./Modals/LayersUsedByModal/LayersUsedByModal";
+import UpdateDatasetModal from "./Modals/UpdateDatasetModal/UpdateDatasetModal";
+import DeleteDatasetModal from "./Modals/DeleteDatasetModal/DeleteDatasetModal";
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
@@ -169,15 +161,12 @@ const useStyles = makeStyles((theme) => ({
minHeight: "48px !important",
display: "flex",
justifyContent: "space-between",
- background: theme.palette.swatches.grey[1000],
- boxShadow: `inset 10px 0px 10px -5px rgba(0,0,0,0.3)`,
- borderBottom: `2px solid ${theme.palette.swatches.grey[800]} !important`,
padding: `0px 20px`,
boxSizing: `border-box !important`,
},
topbarTitle: {
display: "flex",
- color: theme.palette.accent.main,
+ color: theme.palette.swatches.grey[150],
"& > svg": {
color: theme.palette.swatches.grey[150],
margin: "3px 10px 0px 2px",
@@ -213,7 +202,7 @@ const headCells = [
];
function EnhancedTableHead(props) {
- const { order, orderBy, rowCount, onRequestSort } = props;
+ const { order, orderBy, onRequestSort } = props;
const createSortHandler = (property) => (event) => {
onRequestSort(event, property);
};
@@ -420,6 +409,7 @@ export default function Datasets() {
title="Used By"
aria-label="used by"
onClick={() => {
+ console.log(row);
dispatch(
setModal({
name: "layersUsedByDataset",
@@ -437,23 +427,6 @@ export default function Datasets() {
-
- {
- dispatch(
- setModal({
- name: "previewDataset",
- dataset: row,
- })
- );
- }}
- >
-
-
-
{
if (row.name)
calls.api(
- "datasets_get",
+ "datasets_download",
{
layer: row.name,
},
@@ -470,7 +443,7 @@ export default function Datasets() {
downloadObject(
res,
`${row.name}-dataset`,
- ".geojson"
+ ".json"
);
dispatch(
setSnackBarText({
@@ -498,23 +471,6 @@ export default function Datasets() {
-
- {
- dispatch(
- setModal({
- name: "appendDataset",
- dataset: row,
- })
- );
- }}
- >
-
-
-
{/*
- {/*
-
-
-
- */}
+
>
);
}
diff --git a/configure/src/pages/Datasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js b/configure/src/pages/Datasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js
deleted file mode 100644
index 1a52f3e4..00000000
--- a/configure/src/pages/Datasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js
+++ /dev/null
@@ -1,367 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { useSelector, useDispatch } from "react-redux";
-
-import { calls } from "../../../../core/calls";
-
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
-
-import Typography from "@mui/material/Typography";
-import Button from "@mui/material/Button";
-import Dialog from "@mui/material/Dialog";
-import DialogActions from "@mui/material/DialogActions";
-import DialogContent from "@mui/material/DialogContent";
-import DialogTitle from "@mui/material/DialogTitle";
-import IconButton from "@mui/material/IconButton";
-
-import CloseSharpIcon from "@mui/icons-material/CloseSharp";
-import ControlPointDuplicateIcon from "@mui/icons-material/ControlPointDuplicate";
-import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
-
-import { useDropzone } from "react-dropzone";
-
-import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
-
-import { makeStyles, useTheme } from "@mui/styles";
-import useMediaQuery from "@mui/material/useMediaQuery";
-
-const useStyles = makeStyles((theme) => ({
- Modal: {
- margin: theme.headHeights[1],
- [theme.breakpoints.down("xs")]: {
- margin: "6px",
- },
- "& .MuiDialog-container": {
- height: "unset !important",
- transform: "translateX(-50%) translateY(-50%)",
- left: "50%",
- top: "50%",
- position: "absolute",
- },
- },
- contents: {
- background: theme.palette.primary.main,
- height: "100%",
- width: "600px",
- },
- heading: {
- height: theme.headHeights[2],
- boxSizing: "border-box",
- background: theme.palette.swatches.p[0],
- borderBottom: `1px solid ${theme.palette.swatches.grey[800]}`,
- padding: `4px ${theme.spacing(2)} 4px ${theme.spacing(4)} !important`,
- },
- title: {
- padding: `8px 0px`,
- fontSize: theme.typography.pxToRem(16),
- fontWeight: "bold",
- textTransform: "uppercase",
- },
- content: {
- padding: "8px 16px 16px 16px !important",
- height: `calc(100% - ${theme.headHeights[2]}px)`,
- },
- closeIcon: {
- padding: theme.spacing(1.5),
- height: "100%",
- margin: "4px 0px",
- },
- flexBetween: {
- display: "flex",
- justifyContent: "space-between",
- },
- subtitle: {
- fontSize: "14px !important",
- width: "100%",
- marginBottom: "8px !important",
- color: theme.palette.swatches.grey[300],
- letterSpacing: "0.2px",
- },
- subtitle2: {
- fontSize: "12px !important",
- fontStyle: "italic",
- width: "100%",
- marginBottom: "8px !important",
- color: theme.palette.swatches.grey[400],
- },
- missionNameInput: {
- width: "100%",
- margin: "8px 0px 4px 0px !important",
- },
- backgroundIcon: {
- margin: "7px 8px 0px 0px",
- },
-
- fileName: {
- textAlign: "center",
- fontWeight: "bold",
- letterSpacing: "1px",
- marginBottom: "10px",
- paddingBottom: "10px",
- borderBottom: `1px solid ${theme.palette.swatches.grey[500]}`,
- },
- dropzone: {
- width: "100%",
- minHeight: "100px",
- margin: "16px 0px",
- "& > div": {
- flex: "1 1 0%",
- display: "flex",
- flexDirection: "column",
- alignItems: "center",
- padding: "20px",
- borderWidth: "2px",
- borderRadius: "2px",
- borderColor: theme.palette.swatches.grey[300],
- borderStyle: "dashed",
- backgroundColor: theme.palette.swatches.grey[900],
- color: theme.palette.swatches.grey[200],
- outline: "none",
- transition: "border 0.24s ease-in-out 0s",
- "&:hover": {
- borderColor: theme.palette.swatches.p[11],
- },
- },
- },
- dropzoneMessage: {
- textAlign: "center",
- color: theme.palette.swatches.p[11],
- "& > p:first-child": { fontWeight: "bold", letterSpacing: "1px" },
- "& > p:last-child": { fontSize: "14px", fontStyle: "italic" },
- },
- timeFields: {
- display: "flex",
- "& > div:first-child": {
- marginRight: "5px",
- },
- "& > div:last-child": {
- marginLeft: "5px",
- },
- },
-}));
-
-const MODAL_NAME = "appendGeoDataset";
-const AppendGeoDatasetModal = (props) => {
- const { queryGeoDatasets } = props;
- const c = useStyles();
-
- const modal = useSelector((state) => state.core.modal[MODAL_NAME]);
-
- const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down("md"));
-
- const dispatch = useDispatch();
-
- const [geojson, setGeojson] = useState(null);
- const [fileName, setFileName] = useState(null);
- const [startTimeField, setStartTimeField] = useState(null);
- const [endTimeField, setEndTimeField] = useState(null);
-
- useEffect(() => {
- setStartTimeField(modal?.geoDataset?.start_time_field);
- setEndTimeField(modal?.geoDataset?.end_time_field);
- }, [JSON.stringify(modal)]);
-
- const handleClose = () => {
- // close modal
- dispatch(setModal({ name: MODAL_NAME, on: false }));
- };
- const handleSubmit = () => {
- const geoDatasetName = modal?.geoDataset?.name;
-
- if (geojson == null || fileName === null) {
- dispatch(
- setSnackBarText({
- text: "Please upload a file.",
- severity: "error",
- })
- );
- return;
- }
-
- if (geoDatasetName === null) {
- dispatch(
- setSnackBarText({
- text: "No GeoDataset found to append to.",
- severity: "error",
- })
- );
- return;
- }
- const forceParams = {
- filename: fileName,
- };
- if (startTimeField) forceParams.start_prop = startTimeField;
- if (endTimeField) forceParams.end_prop = endTimeField;
-
- calls.api(
- "geodatasets_append",
- {
- urlReplacements: {
- name: geoDatasetName,
- },
- forceParams,
- type: geojson.type,
- features: geojson.features,
- },
- (res) => {
- if (res.status === "success") {
- dispatch(
- setSnackBarText({
- text: "Successfully appended to GeoDataset.",
- severity: "success",
- })
- );
- queryGeoDatasets();
- handleClose();
- } else {
- dispatch(
- setSnackBarText({
- text: res?.message || "Failed to append to GeoDataset.",
- severity: "error",
- })
- );
- }
- },
- (res) => {
- dispatch(
- setSnackBarText({
- text: res?.message || "Failed to append to GeoDataset.",
- severity: "error",
- })
- );
- }
- );
- };
-
- // Dropzone initialization
- const {
- getRootProps,
- getInputProps,
- isDragActive,
- isDragAccept,
- isDragReject,
- } = useDropzone({
- maxFiles: 1,
- accept: {
- "application/json": [".json", ".geojson"],
- },
- onDropAccepted: (files) => {
- const file = files[0];
- setFileName(file.name);
-
- const reader = new FileReader();
- reader.onload = (e) => {
- setGeojson(JSON.parse(e.target.result));
- };
- reader.readAsText(file);
- },
- onDropRejected: () => {
- setFileName(null);
- setGeojson(null);
- },
- });
-
- return (
-
-
-
-
-
-
{`Append features to this GeoDataset: ${modal?.geoDataset?.name}`}
-
-
-
-
-
-
-
-
- {`Appends the features of the uploaded file to the GeoDataset`}
-
-
-
-
- {isDragAccept &&
All files will be accepted
}
- {isDragReject &&
Some files will be rejected
}
- {!isDragActive && (
-
-
Drag 'n' drop or click to select files...
-
Only *.json and *.geojson files are accepted.
-
- )}
-
-
-
-
-
-
{fileName || "No File Selected"}
-
-
-
-
- {
- setStartTimeField(e.target.value);
- }}
- />
-
- {`If this GeoDataset already has a Start Time Field attached, the name of that start time field inside each feature's "properties" object for which to create a temporal index for the geodataset. Take care in using time field names for the appended GeoJSON features that are different from that of the existing features.`}
-
-
-
- {
- setEndTimeField(e.target.value);
- }}
- />
-
- {`If this GeoDataset already has a End Time Field attached, the name of that end time field inside each feature's "properties" object for which to create a temporal index for the geodataset. Take care in using time field names for the appended GeoJSON features that are different from that of the existing features.`}
-
-
-
-
-
-
- Append to GeoDataset
-
-
-
- );
-};
-
-export default AppendGeoDatasetModal;
diff --git a/configure/src/pages/Datasets/Modals/DeleteGeoDatasetModal/DeleteGeoDatasetModal.js b/configure/src/pages/Datasets/Modals/DeleteDatasetModal/DeleteDatasetModal.js
similarity index 83%
rename from configure/src/pages/Datasets/Modals/DeleteGeoDatasetModal/DeleteGeoDatasetModal.js
rename to configure/src/pages/Datasets/Modals/DeleteDatasetModal/DeleteDatasetModal.js
index 16133650..22286621 100644
--- a/configure/src/pages/Datasets/Modals/DeleteGeoDatasetModal/DeleteGeoDatasetModal.js
+++ b/configure/src/pages/Datasets/Modals/DeleteDatasetModal/DeleteDatasetModal.js
@@ -161,40 +161,40 @@ const useStyles = makeStyles((theme) => ({
cancel: {},
}));
-const MODAL_NAME = "deleteGeoDataset";
-const DeleteGeoDatasetModal = (props) => {
- const { queryGeoDatasets } = props;
+const MODAL_NAME = "deleteDataset";
+const DeleteDatasetModal = (props) => {
+ const { queryDatasets } = props;
const c = useStyles();
const modal = useSelector((state) => state.core.modal[MODAL_NAME]);
- const geodatasets = useSelector((state) => state.core.geodatasets);
+ const datasets = useSelector((state) => state.core.datasets);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const dispatch = useDispatch();
- const [geoDatasetName, setGeoDatasetName] = useState(null);
+ const [datasetName, setDatasetName] = useState(null);
const handleClose = () => {
// close modal
dispatch(setModal({ name: MODAL_NAME, on: false }));
};
const handleSubmit = () => {
- if (!modal?.geoDataset?.name) {
+ if (!modal?.dataset?.name) {
dispatch(
setSnackBarText({
- text: "Cannot delete undefined GeoDataset.",
+ text: "Cannot delete undefined Dataset.",
severity: "error",
})
);
return;
}
- if (geoDatasetName !== modal.geoDataset.name) {
+ if (datasetName !== modal.dataset.name) {
dispatch(
setSnackBarText({
- text: "Confirmation GeoDataset name does not match.",
+ text: "Confirmation Dataset name does not match.",
severity: "error",
})
);
@@ -202,26 +202,26 @@ const DeleteGeoDatasetModal = (props) => {
}
calls.api(
- "geodatasets_remove",
+ "datasets_remove",
{
urlReplacements: {
- name: modal.geoDataset.name,
+ name: modal.dataset.name,
},
},
(res) => {
if (res.status === "success") {
dispatch(
setSnackBarText({
- text: `Successfully deleted the '${modal.geoDataset.name}' GeoDataset.`,
+ text: `Successfully deleted the '${modal.dataset.name}' Dataset.`,
severity: "success",
})
);
- queryGeoDatasets();
+ queryDatasets();
handleClose();
} else {
dispatch(
setSnackBarText({
- text: `Failed to delete the '${modal.geoDataset.name}' GeoDataset.`,
+ text: `Failed to delete the '${modal.dataset.name}' Dataset.`,
severity: "error",
})
);
@@ -230,7 +230,7 @@ const DeleteGeoDatasetModal = (props) => {
(res) => {
dispatch(
setSnackBarText({
- text: `Failed to delete the '${modal.geoDataset.name}' GeoDataset.`,
+ text: `Failed to delete the '${modal.dataset.name}' Dataset.`,
severity: "error",
})
);
@@ -240,10 +240,10 @@ const DeleteGeoDatasetModal = (props) => {
let occurrences = [];
- if (modal?.geoDataset?.occurrences)
- occurrences = Object.keys(modal?.geoDataset?.occurrences)
+ if (modal?.dataset?.occurrences)
+ occurrences = Object.keys(modal?.dataset?.occurrences)
.map((mission) => {
- const m = modal?.geoDataset?.occurrences[mission];
+ const m = modal?.dataset?.occurrences[mission];
if (m.length == 0) return null;
else {
const items = [{mission}
];
@@ -277,7 +277,7 @@ const DeleteGeoDatasetModal = (props) => {
-
Delete a GeoDataset
+
Delete a Dataset
{
{`Deleting: ${modal?.geoDataset?.name}`}
+ >{`Deleting: ${modal?.dataset?.name}`}
{occurrences.length > 0 && (
<>
- {`This GeoDataset is currently in use in the following layers:`}
+ {`This Dataset is currently in use in the following layers:`}
{occurrences}
@@ -306,25 +306,26 @@ const DeleteGeoDatasetModal = (props) => {
)}
{
- setGeoDatasetName(e.target.value);
+ setDatasetName(e.target.value);
}}
/>
{`Enter '${modal?.geoDataset?.name}' above and click 'Delete' to confirm the permanent deletion of this GeoDataset.`}
+ >{`Enter '${modal?.dataset?.name}' above and click 'Delete' to confirm the permanent deletion of this Dataset.`}
}
- onClick={handleSubmit}
+ onClick={() => {}}
+ style={{ cursor: "not-allowed" }}
>
- Delete
+ Not Implemented
Cancel
@@ -334,4 +335,4 @@ const DeleteGeoDatasetModal = (props) => {
);
};
-export default DeleteGeoDatasetModal;
+export default DeleteDatasetModal;
diff --git a/configure/src/pages/Datasets/Modals/LayersUsedByModal/LayersUsedByModal.js b/configure/src/pages/Datasets/Modals/LayersUsedByModal/LayersUsedByModal.js
index 558bd613..f3a8ee59 100644
--- a/configure/src/pages/Datasets/Modals/LayersUsedByModal/LayersUsedByModal.js
+++ b/configure/src/pages/Datasets/Modals/LayersUsedByModal/LayersUsedByModal.js
@@ -1,9 +1,7 @@
-import React, { useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
-import { calls } from "../../../../core/calls";
-
-import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
+import { setModal } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -15,10 +13,6 @@ import IconButton from "@mui/material/IconButton";
import CloseSharpIcon from "@mui/icons-material/CloseSharp";
import ShapeLineIcon from "@mui/icons-material/ShapeLine";
-import WarningIcon from "@mui/icons-material/Warning";
-import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
-
-import TextField from "@mui/material/TextField";
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
@@ -127,7 +121,7 @@ const useStyles = makeStyles((theme) => ({
close: {},
}));
-const MODAL_NAME = "layersUsedByGeoDataset";
+const MODAL_NAME = "layersUsedByDataset";
const LayersUsedByModal = (props) => {
const {} = props;
const c = useStyles();
@@ -146,10 +140,10 @@ const LayersUsedByModal = (props) => {
let occurrences = [];
- if (modal?.geoDataset?.occurrences)
- occurrences = Object.keys(modal?.geoDataset?.occurrences)
+ if (modal?.dataset?.occurrences)
+ occurrences = Object.keys(modal?.dataset?.occurrences)
.map((mission) => {
- const m = modal?.geoDataset?.occurrences[mission];
+ const m = modal?.dataset?.occurrences[mission];
if (m.length == 0) return null;
else {
const items = [{mission}
];
@@ -183,7 +177,7 @@ const LayersUsedByModal = (props) => {
-
GeoDataset is Used By
+
Dataset is Used By
{
{`${modal?.geoDataset?.name}`}
+ >{`${modal?.dataset?.name}`}
{occurrences.length > 0 ? (
<>
- {`This GeoDataset is currently in use in the following layers:`}
+ {`This Dataset is currently in use in the following layers:`}
{occurrences}
@@ -211,7 +205,7 @@ const LayersUsedByModal = (props) => {
) : (
- {`This GeoDataset is not in use.`}
+ {`This Dataset is not in use.`}
)}
diff --git a/configure/src/pages/Datasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js b/configure/src/pages/Datasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js
deleted file mode 100644
index 61c09848..00000000
--- a/configure/src/pages/Datasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js
+++ /dev/null
@@ -1,160 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { useSelector, useDispatch } from "react-redux";
-
-import { calls } from "../../../../core/calls";
-
-import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
-
-import Typography from "@mui/material/Typography";
-import Button from "@mui/material/Button";
-import Dialog from "@mui/material/Dialog";
-import DialogActions from "@mui/material/DialogActions";
-import DialogContent from "@mui/material/DialogContent";
-import DialogTitle from "@mui/material/DialogTitle";
-import IconButton from "@mui/material/IconButton";
-
-import CloseSharpIcon from "@mui/icons-material/CloseSharp";
-import PreviewIcon from "@mui/icons-material/Preview";
-
-import { makeStyles, useTheme } from "@mui/styles";
-import useMediaQuery from "@mui/material/useMediaQuery";
-import Map from "../../../../components/Map/Map";
-
-const useStyles = makeStyles((theme) => ({
- Modal: {
- [theme.breakpoints.down("xs")]: {
- margin: "6px",
- },
- "& .MuiDialog-container": {
- width: "100%",
- transform: "translateX(-50%) translateY(-50%)",
- left: "50%",
- top: "50%",
- position: "absolute",
- },
- "& .MuiPaper-root": {
- margin: "0px",
- },
- },
- contents: {
- height: "100%",
- width: "100%",
- maxWidth: "calc(100vw - 32px) !important",
- maxHeight: "calc(100vh - 32px) !important",
- },
- heading: {
- height: theme.headHeights[2],
- boxSizing: "border-box",
- background: theme.palette.swatches.p[0],
- padding: `4px ${theme.spacing(2)} 4px ${theme.spacing(4)} !important`,
- },
- title: {
- padding: `8px 0px`,
- fontSize: theme.typography.pxToRem(16),
- fontWeight: "bold",
- textTransform: "uppercase",
- },
- content: {
- padding: "0px !important",
- height: `calc(100vh - 32px)`,
- background: theme.palette.swatches.grey[100],
- },
- closeIcon: {
- padding: theme.spacing(1.5),
- height: "100%",
- margin: "4px 0px",
- },
- flexBetween: {
- display: "flex",
- justifyContent: "space-between",
- },
- backgroundIcon: {
- margin: "7px 8px 0px 0px",
- },
-}));
-
-const MODAL_NAME = "previewGeoDataset";
-const PreviewGeoDatasetModal = (props) => {
- const {} = props;
- const c = useStyles();
-
- const modal = useSelector((state) => state.core.modal[MODAL_NAME]);
- const [geoDataset, setGeoDataset] = useState(null);
-
- const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down("md"));
-
- const dispatch = useDispatch();
-
- const handleClose = () => {
- // close modal
- dispatch(setModal({ name: MODAL_NAME, on: false }));
- };
-
- const queryGeoDataset = () => {
- if (modal?.geoDataset?.name)
- calls.api(
- "geodatasets_get",
- {
- layer: modal.geoDataset.name,
- },
- (res) => {
- setGeoDataset(res);
- },
- (res) => {
- dispatch(
- setSnackBarText({
- text: res?.message || "Failed to get geodataset.",
- severity: "error",
- })
- );
- }
- );
- };
- useEffect(() => {
- queryGeoDataset();
- }, [modal?.geoDataset?.name]);
-
- return (
-
-
-
-
-
-
{`Previewing GeoDataset${
- modal?.geoDataset?.name ? `: ${modal.geoDataset.name}` : ""
- }`}
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default PreviewGeoDatasetModal;
diff --git a/configure/src/pages/Datasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js b/configure/src/pages/Datasets/Modals/UpdateDatasetModal/UpdateDatasetModal.js
similarity index 62%
rename from configure/src/pages/Datasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js
rename to configure/src/pages/Datasets/Modals/UpdateDatasetModal/UpdateDatasetModal.js
index 49905d69..e15f9993 100644
--- a/configure/src/pages/Datasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js
+++ b/configure/src/pages/Datasets/Modals/UpdateDatasetModal/UpdateDatasetModal.js
@@ -1,13 +1,11 @@
-import React, { useState, useEffect } from "react";
+import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
+import Papa from "papaparse";
+
import { calls } from "../../../../core/calls";
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
+import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -16,6 +14,7 @@ import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import IconButton from "@mui/material/IconButton";
+import LinearProgress from "@mui/material/LinearProgress";
import CloseSharpIcon from "@mui/icons-material/CloseSharp";
import UploadIcon from "@mui/icons-material/Upload";
@@ -23,11 +22,6 @@ import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
import { useDropzone } from "react-dropzone";
-import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
-
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
@@ -146,9 +140,9 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const MODAL_NAME = "updateGeoDataset";
-const UpdateGeoDatasetModal = (props) => {
- const { queryGeoDatasets } = props;
+const MODAL_NAME = "updateDataset";
+const UpdateDatasetModal = (props) => {
+ const { queryDatasets } = props;
const c = useStyles();
const modal = useSelector((state) => state.core.modal[MODAL_NAME]);
@@ -158,24 +152,18 @@ const UpdateGeoDatasetModal = (props) => {
const dispatch = useDispatch();
- const [geojson, setGeojson] = useState(null);
const [fileName, setFileName] = useState(null);
- const [startTimeField, setStartTimeField] = useState(null);
- const [endTimeField, setEndTimeField] = useState(null);
-
- useEffect(() => {
- setStartTimeField(modal?.geoDataset?.start_time_field);
- setEndTimeField(modal?.geoDataset?.end_time_field);
- }, [JSON.stringify(modal)]);
+ const [file, setFile] = useState(null);
+ const [progress, setProgress] = useState(null);
const handleClose = () => {
// close modal
dispatch(setModal({ name: MODAL_NAME, on: false }));
};
const handleSubmit = () => {
- const geoDatasetName = modal?.geoDataset?.name;
+ const datasetName = modal?.dataset?.name;
- if (geojson == null || fileName === null) {
+ if (file == null || fileName === null) {
dispatch(
setSnackBarText({
text: "Please upload a file.",
@@ -185,53 +173,117 @@ const UpdateGeoDatasetModal = (props) => {
return;
}
- if (geoDatasetName === null) {
+ if (datasetName == null || datasetName == "") {
+ dispatch(
+ setSnackBarText({
+ text: "Missing Dataset name.",
+ severity: "error",
+ })
+ );
+ return;
+ }
+
+ if (datasetName.match(/[|\\/~^:,;?!&%$@#*+\{\}\[\]<>]/)) {
dispatch(
setSnackBarText({
- text: "No GeoDataset found to update.",
+ text: "Dataset names cannot contain the following symbols: |\\/~^:,;?!&%$@#*+.{}[]<>",
severity: "error",
})
);
return;
}
- calls.api(
- "geodatasets_recreate",
- {
- name: geoDatasetName,
- startProp: startTimeField,
- endProp: endTimeField,
- geojson: geojson,
- filename: fileName,
+ const rowsPerChunk = 10000;
+ let currentRows = [];
+ let header = [];
+ let first = true;
+ let firstStep = true;
+ let cursorSum = 0;
+ let cursorStep = null;
+ Papa.parse(file, {
+ step: (row, parser) => {
+ if (firstStep) {
+ header = row.data;
+ firstStep = false;
+ } else {
+ let r = {};
+ for (let i = 0; i < header.length; i++) r[header[i]] = row.data[i];
+ currentRows.push(r);
+
+ if (currentRows.length >= rowsPerChunk) {
+ cursorStep = cursorStep || row.meta.cursor;
+ cursorSum += cursorStep;
+ setProgress(Math.round((cursorSum / file.size) * 100));
+
+ parser.pause();
+
+ calls.api(
+ "datasets_recreate",
+ {
+ name: datasetName,
+ csv: JSON.stringify(currentRows),
+ header: header,
+ mode: first ? "full" : "append",
+ },
+ (res) => {
+ first = false;
+ currentRows = [];
+ parser.resume();
+ },
+ (res) => {
+ currentRows = [];
+ console.log(res?.message);
+ dispatch(
+ setSnackBarText({
+ text: "Failed to upload a Dataset.",
+ severity: "error",
+ })
+ );
+ }
+ );
+ }
+ }
},
- (res) => {
- if (res.status === "success") {
- dispatch(
- setSnackBarText({
- text: "Successfully updated GeoDataset.",
- severity: "success",
- })
+ complete: function () {
+ if (currentRows.length > 0) {
+ calls.api(
+ "datasets_recreate",
+ {
+ name: datasetName,
+ csv: JSON.stringify(currentRows),
+ header: header,
+ mode: "append",
+ },
+ (res) => {
+ dispatch(
+ setSnackBarText({
+ text: "Successfully updated/replaced Dataset.",
+ severity: "success",
+ })
+ );
+ queryDatasets();
+ setProgress(null);
+ handleClose();
+ },
+ (res) => {
+ currentRows = [];
+ console.log(res?.message);
+ dispatch(
+ setSnackBarText({
+ text: "Failed to upload a Dataset.",
+ severity: "error",
+ })
+ );
+ }
);
- queryGeoDatasets();
- handleClose();
} else {
- dispatch(
- setSnackBarText({
- text: res?.message || "Failed to update GeoDataset.",
- severity: "error",
- })
- );
+ queryDatasets();
+ setProgress(null);
}
},
- (res) => {
- dispatch(
- setSnackBarText({
- text: res?.message || "Failed to update GeoDataset.",
- severity: "error",
- })
- );
- }
- );
+ });
+
+ return;
};
// Dropzone initialization
@@ -244,24 +296,18 @@ const UpdateGeoDatasetModal = (props) => {
} = useDropzone({
maxFiles: 1,
accept: {
- "application/json": [".json", ".geojson"],
+ "application/csv": [".csv"],
},
onDropAccepted: (files) => {
- const file = files[0];
- setFileName(file.name);
-
- const reader = new FileReader();
- reader.onload = (e) => {
- setGeojson(JSON.parse(e.target.result));
- };
- reader.readAsText(file);
+ const uploadedFile = files[0];
+ setFileName(uploadedFile.name);
+ setFile(uploadedFile);
},
onDropRejected: () => {
setFileName(null);
- setGeojson(null);
+ setFile(null);
},
});
-
return (
{
{`Update/Replace this GeoDataset: ${modal?.geoDataset?.name}`}
+ >{`Update/Replace this Dataset: ${modal?.dataset?.name}`}
{
- {`Overwrites the contents of the existing GeoDataset with that of the uploaded file.`}
+ {`Overwrites the contents of the existing Dataset with that of the uploaded file.`}
@@ -303,7 +349,7 @@ const UpdateGeoDatasetModal = (props) => {
{!isDragActive && (
Drag 'n' drop or click to select files...
-
Only *.json and *.geojson files are accepted.
+
Only *.csv files are accepted.
)}
@@ -313,49 +359,21 @@ const UpdateGeoDatasetModal = (props) => {
{fileName || "No File Selected"}
-
-
-
- {
- setStartTimeField(e.target.value);
- }}
- />
-
- {`If this GeoDataset already has a Start Time Field attached, the name of that start time field inside each feature's "properties" object for which to create a temporal index for the geodataset. `}
-
-
-
- {
- setEndTimeField(e.target.value);
- }}
- />
-
- {`If this GeoDataset already has a End Time Field attached, the name of that end time field inside each feature's "properties" object for which to create a temporal index for the geodataset. This enables time queries on GeoDatasets. `}
-
-
-
+ {progress != null && (
+
+ )}
- Update/Replace GeoDataset
+ Update/Replace Dataset
);
};
-export default UpdateGeoDatasetModal;
+export default UpdateDatasetModal;
diff --git a/configure/src/pages/GeoDatasets/GeoDatasets.js b/configure/src/pages/GeoDatasets/GeoDatasets.js
index dee4d482..b8fe5fa3 100644
--- a/configure/src/pages/GeoDatasets/GeoDatasets.js
+++ b/configure/src/pages/GeoDatasets/GeoDatasets.js
@@ -1,9 +1,7 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
-import clsx from "clsx";
-
import { calls } from "../../core/calls";
import { downloadObject } from "../../core/utils";
import {
@@ -26,14 +24,9 @@ import TableSortLabel from "@mui/material/TableSortLabel";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
-import Checkbox from "@mui/material/Checkbox";
import IconButton from "@mui/material/IconButton";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Switch from "@mui/material/Switch";
-import DeleteIcon from "@mui/icons-material/Delete";
-import FilterListIcon from "@mui/icons-material/FilterList";
import Divider from "@mui/material/Divider";
import Badge from "@mui/material/Badge";
import { visuallyHidden } from "@mui/utils";
@@ -42,7 +35,6 @@ import InventoryIcon from "@mui/icons-material/Inventory";
import PreviewIcon from "@mui/icons-material/Preview";
import DownloadIcon from "@mui/icons-material/Download";
import UploadIcon from "@mui/icons-material/Upload";
-import DriveFileRenameOutlineIcon from "@mui/icons-material/DriveFileRenameOutline";
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
import AddIcon from "@mui/icons-material/Add";
import ShapeLineIcon from "@mui/icons-material/ShapeLine";
@@ -174,15 +166,12 @@ const useStyles = makeStyles((theme) => ({
minHeight: "48px !important",
display: "flex",
justifyContent: "space-between",
- background: theme.palette.swatches.grey[1000],
- boxShadow: `inset 10px 0px 10px -5px rgba(0,0,0,0.3)`,
- borderBottom: `2px solid ${theme.palette.swatches.grey[800]} !important`,
padding: `0px 20px`,
boxSizing: `border-box !important`,
},
topbarTitle: {
display: "flex",
- color: theme.palette.accent.main,
+ color: theme.palette.swatches.grey[150],
"& > svg": {
color: theme.palette.swatches.grey[150],
margin: "3px 10px 0px 2px",
diff --git a/configure/src/pages/GeoDatasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js b/configure/src/pages/GeoDatasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js
index 1a52f3e4..cb96b837 100644
--- a/configure/src/pages/GeoDatasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js
+++ b/configure/src/pages/GeoDatasets/Modals/AppendGeoDatasetModal/AppendGeoDatasetModal.js
@@ -3,11 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
import { calls } from "../../../../core/calls";
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
+import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -24,9 +20,6 @@ import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
import { useDropzone } from "react-dropzone";
import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
diff --git a/configure/src/pages/GeoDatasets/Modals/LayersUsedByModal/LayersUsedByModal.js b/configure/src/pages/GeoDatasets/Modals/LayersUsedByModal/LayersUsedByModal.js
index 558bd613..45130b7b 100644
--- a/configure/src/pages/GeoDatasets/Modals/LayersUsedByModal/LayersUsedByModal.js
+++ b/configure/src/pages/GeoDatasets/Modals/LayersUsedByModal/LayersUsedByModal.js
@@ -1,9 +1,7 @@
-import React, { useState } from "react";
+import React from "react";
import { useSelector, useDispatch } from "react-redux";
-import { calls } from "../../../../core/calls";
-
-import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
+import { setModal } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -15,10 +13,6 @@ import IconButton from "@mui/material/IconButton";
import CloseSharpIcon from "@mui/icons-material/CloseSharp";
import ShapeLineIcon from "@mui/icons-material/ShapeLine";
-import WarningIcon from "@mui/icons-material/Warning";
-import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
-
-import TextField from "@mui/material/TextField";
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
diff --git a/configure/src/pages/GeoDatasets/Modals/NewGeoDatasetModal/NewGeoDatasetModal.js b/configure/src/pages/GeoDatasets/Modals/NewGeoDatasetModal/NewGeoDatasetModal.js
index 3b6d267f..3bf1b8fa 100644
--- a/configure/src/pages/GeoDatasets/Modals/NewGeoDatasetModal/NewGeoDatasetModal.js
+++ b/configure/src/pages/GeoDatasets/Modals/NewGeoDatasetModal/NewGeoDatasetModal.js
@@ -3,11 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
import { calls } from "../../../../core/calls";
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
+import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -24,9 +20,6 @@ import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
import { useDropzone } from "react-dropzone";
import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
diff --git a/configure/src/pages/GeoDatasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js b/configure/src/pages/GeoDatasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js
index 61c09848..3c0918e4 100644
--- a/configure/src/pages/GeoDatasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js
+++ b/configure/src/pages/GeoDatasets/Modals/PreviewGeoDatasetModal/PreviewGeoDatasetModal.js
@@ -5,10 +5,7 @@ import { calls } from "../../../../core/calls";
import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
-import Typography from "@mui/material/Typography";
-import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
-import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import IconButton from "@mui/material/IconButton";
diff --git a/configure/src/pages/GeoDatasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js b/configure/src/pages/GeoDatasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js
index 49905d69..62e0c68b 100644
--- a/configure/src/pages/GeoDatasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js
+++ b/configure/src/pages/GeoDatasets/Modals/UpdateGeoDatasetModal/UpdateGeoDatasetModal.js
@@ -3,11 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
import { calls } from "../../../../core/calls";
-import {
- setMissions,
- setModal,
- setSnackBarText,
-} from "../../../../core/ConfigureStore";
+import { setModal, setSnackBarText } from "../../../../core/ConfigureStore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -24,9 +20,6 @@ import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
import { useDropzone } from "react-dropzone";
import TextField from "@mui/material/TextField";
-import FormGroup from "@mui/material/FormGroup";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
import { makeStyles, useTheme } from "@mui/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
diff --git a/configure/src/pages/WebHooks/WebHooks.js b/configure/src/pages/WebHooks/WebHooks.js
index 221faef6..38b4e70d 100644
--- a/configure/src/pages/WebHooks/WebHooks.js
+++ b/configure/src/pages/WebHooks/WebHooks.js
@@ -1,23 +1,29 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { makeStyles } from "@mui/styles";
import { calls } from "../../core/calls";
+import { getIn } from "../../core/utils";
import Maker from "../../core/Maker";
-import { setSnackBarText } from "../../core/ConfigureStore";
+import { setSnackBarText, setConfiguration } from "../../core/ConfigureStore";
+
+import Button from "@mui/material/Button";
+
+import SaveIcon from "@mui/icons-material/Save";
+import PhishingIcon from "@mui/icons-material/Phishing";
const config = {
rows: [
{
- name: "WebHooks",
+ name: "Webhooks",
description:
- "Configures the available functionalities of the Map's and Globe's right-click context menu.",
+ "Trigger HTTP requests whenever certain actions are executed in MMGIS.",
components: [
{
- field: "webhooks",
- name: "Context Menu Actions",
+ field: "temp.webhooks",
+ name: "Webhooks",
description:
- "When right-clicking on the Map or Globe, a custom context-menu appears. By default it only offers 'Copy Coordinates'. By adding objects to the rightClickMenuActions array, entries can be added to the context-menu to send users to links with parameters populated with the current coordinates.",
+ "Configure HTTP requests whenever certain actions are executed in MMGIS.",
type: "objectarray",
width: 12,
object: [
@@ -25,7 +31,7 @@ const config = {
field: "action",
name: "Action",
description:
- "Optionally restrict some right-click menu actions to only be supported when clicking on a polygon.",
+ "Which action upon which to trigger the webhook request.",
type: "dropdown",
width: 2,
options: ["DrawFileAdd", "DrawFileChange", "DrawFileDelete"],
@@ -33,8 +39,7 @@ const config = {
{
field: "type",
name: "HTTP Method",
- description:
- "Optionally restrict some right-click menu actions to only be supported when clicking on a polygon.",
+ description: "The HTTP method for which to send the request.",
type: "dropdown",
width: 2,
options: ["GET", "POST", "PUT", "DELETE", "PATCH"],
@@ -43,25 +48,27 @@ const config = {
field: "url",
name: "URL",
description:
- "The text for this menu entry when users right-click.",
+ "The URL for which to send the request. Valid injectable variables for URL: {created_on}, {efolders}, {file_description}, {file_id}, {file_name}, {file_owner}, {file_owner_group}, {folders}, {geojson}, {hidden}, {intent}, {is_master}, {public}, {public_editors}, {publicity_type}, {raw_file_description}, {tags}, {template}, {updated_on}.",
type: "text",
- width: 2,
+ width: 8,
},
{
field: "header",
name: "Header JSON",
description:
- "Vector Tiles are styled differently than Vectors. Raw variables here takes an object that maps internal vector tile layer names to styles. All raw variables are optional.",
+ 'A JSON object of request headers to use with NodeJS fetch. For example: {"Content-Type": "application/json"}',
type: "json",
width: 12,
+ height: "100px",
},
{
field: "body",
name: "Body JSON",
description:
- "Vector Tiles are styled differently than Vectors. Raw variables here takes an object that maps internal vector tile layer names to styles. All raw variables are optional.",
+ "A JSON object to be the body of the request. MMGIS will auto-replace the following strings contained anywhere in the body before sending it to the URL. Valid injectable variables for Body fields: {created_on}, {efolders}, {file_description}, {file_id}, {file_name}, {file_owner}, {file_owner_group}, {folders}, {geojson}, {hidden}, {intent}, {is_master}, {public}, {public_editors}, {publicity_type}, {raw_file_description}, {tags}, {template}, {updated_on}",
type: "json",
width: 12,
+ height: "180px",
},
],
},
@@ -76,21 +83,126 @@ const useStyles = makeStyles((theme) => ({
height: "100%",
overflowY: "auto",
display: "flex",
+ flexFlow: "column",
background: theme.palette.swatches.grey[1000],
padding: "0px 32px 64px 32px",
boxSizing: "border-box",
backgroundImage: "url(configure/build/gridlines.png)",
},
+ gap: {
+ height: "64px",
+ width: "100%",
+ },
+ save: {
+ margin: "8px !important",
+ height: "32px",
+ borderRadius: "3px !important",
+ background: `${theme.palette.swatches.p[11]} !important`,
+ color: "white !important",
+ position: "absolute !important",
+ bottom: "0px",
+ right: "5px",
+ },
}));
export default function WebHooks() {
const c = useStyles();
+ const configuration = useSelector((state) => state.core.configuration);
+
const dispatch = useDispatch();
+ const saveWebHooks = () => {
+ let webhooks = getIn(configuration, "temp.webhooks", null);
+
+ if (webhooks != null) {
+ webhooks = JSON.parse(JSON.stringify(webhooks));
+
+ calls.api(
+ "webhooks_save",
+ {
+ config: JSON.stringify({ webhooks }),
+ },
+ (res) => {
+ if (res.status === "success") {
+ dispatch(
+ setSnackBarText({
+ text: "Successfully saved webhooks.",
+ severity: "success",
+ })
+ );
+ } else
+ dispatch(
+ setSnackBarText({
+ text: res?.message || "Failed to save webhooks.",
+ severity: "error",
+ })
+ );
+ },
+ (res) => {
+ dispatch(
+ setSnackBarText({
+ text: res?.message || "Failed to save webhooks.",
+ severity: "error",
+ })
+ );
+ }
+ );
+ }
+ };
+ const queryWebHooks = () => {
+ calls.api(
+ "webhooks_entries",
+ {},
+ (res) => {
+ if (res.status === "success") {
+ if (res.body && res.body.entries && res.body.entries.length > 0) {
+ const config = JSON.parse(res.body.entries[0].config);
+ dispatch(
+ setConfiguration({
+ temp: {
+ webhooks: config.webhooks,
+ },
+ })
+ );
+ }
+ } else
+ dispatch(
+ setSnackBarText({
+ text: res?.message || "Failed to get webhooks.",
+ severity: "error",
+ })
+ );
+ },
+ (res) => {
+ dispatch(
+ setSnackBarText({
+ text: res?.message || "Failed to get webhooks.",
+ severity: "error",
+ })
+ );
+ }
+ );
+ };
+ useEffect(() => {
+ queryWebHooks();
+ }, []);
+
return (
+
+
}
+ endIcon={
}
+ onClick={() => {
+ saveWebHooks();
+ }}
+ >
+ Save Webhooks
+
);
}