This is an automated email from the ASF dual-hosted git repository.
imesha pushed a commit to branch development
in repository https://gitbox.apache.org/repos/asf/oodt.git
The following commit(s) were added to refs/heads/development by this push:
new b375681 Add File Manager NodeJS component and update OPSUI dashboard
new cb77ee4 Merge pull request #112 from NGimhana
b375681 is described below
commit b375681f218190ca01e5e7670a4601632f9c62dc
Author: ngimhana <[email protected]>
AuthorDate: Sat Aug 24 16:18:43 2019 +0530
Add File Manager NodeJS component and update OPSUI dashboard
---
react-components/oodt_fm_plugin/package.json | 5 +-
.../src/components/Product/Product.js | 427 ++++++++++++++-------
.../oodt_fm_plugin/src/components/Product/index.js | 2 +-
.../src/components/ProductIngest/ProductIngest.js | 228 +++++++++++
.../components/{Product => ProductIngest}/index.js | 4 +-
.../ProductIngestWithMetaFile.js | 153 ++++++++
.../index.js | 4 +-
.../src/components/ProductList/ProductList.js | 403 +++++++++++++++++++
.../src/components/ProductList/SearchBar.js | 98 +++++
.../src/components/ProductList/SimpleSnackBar.js | 82 ++++
.../components/{Product => ProductList}/index.js | 4 +-
.../oodt_fm_plugin/src/components/index.js | 7 +-
.../oodt_fm_plugin/src/constants/fmconnection.js | 2 +-
react-components/oodt_fm_plugin/src/index.js | 2 +-
react-components/oodt_opsui_sample_app/README.md | 36 ++
.../oodt_opsui_sample_app/package.json | 36 ++
.../oodt_opsui_sample_app/public/favicon.ico | Bin 0 -> 3870 bytes
.../public/images/oodt_logo.png | Bin 0 -> 28444 bytes
.../oodt_opsui_sample_app/public/index.html | 38 ++
.../oodt_opsui_sample_app/public/manifest.json | 15 +
react-components/oodt_opsui_sample_app/src/App.js | 141 +++++++
.../oodt_opsui_sample_app/src/App.test.js | 9 +
.../src/components/OPSUIHome.js | 244 ++++++++++++
.../src/components/SearchBar.js | 102 +++++
.../src/components/listItems.js | 94 +++++
.../oodt_opsui_sample_app/src/index.css | 13 +
.../oodt_opsui_sample_app/src/index.js | 11 +
.../oodt/cas/product/jaxrs/enums/ErrorType.java | 68 ----
28 files changed, 2007 insertions(+), 221 deletions(-)
diff --git a/react-components/oodt_fm_plugin/package.json
b/react-components/oodt_fm_plugin/package.json
index f81ce33..327ea3d 100644
--- a/react-components/oodt_fm_plugin/package.json
+++ b/react-components/oodt_fm_plugin/package.json
@@ -22,16 +22,19 @@
"license": "Apache-2.0",
"devDependencies": {
"@babel/core": "^7.2.2",
+ "@babel/plugin-proposal-class-properties": "^7.4.0",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
- "@babel/plugin-proposal-class-properties": "^7.4.0",
"babel-loader": "^8.0.5",
+ "prettier": "1.18.2",
"webpack": "^4.28.3",
"webpack-cli": "^3.2.0"
},
"dependencies": {
"@material-ui/core": "^3.9.3",
+ "@material-ui/icons": "^4.2.0",
"axios": "^0.18.0",
+ "clsx": "^1.0.4",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"prop-types": "latest"
diff --git a/react-components/oodt_fm_plugin/src/components/Product/Product.js
b/react-components/oodt_fm_plugin/src/components/Product/Product.js
index c5acc2f..16f353b 100644
--- a/react-components/oodt_fm_plugin/src/components/Product/Product.js
+++ b/react-components/oodt_fm_plugin/src/components/Product/Product.js
@@ -15,170 +15,313 @@
* limitations under the License.
*/
-import React, {Component} from "react";
-import Card from '@material-ui/core/Card';
-import CardContent from '@material-ui/core/CardContent';
-import Button from '@material-ui/core/Button';
-import Typography from '@material-ui/core/Typography';
-import {withStyles} from "@material-ui/core";
+import React, { Component } from "react";
+import Card from "@material-ui/core/Card";
+import CardContent from "@material-ui/core/CardContent";
+import Button from "@material-ui/core/Button";
+import Typography from "@material-ui/core/Typography";
+import { withStyles } from "@material-ui/core";
import PropTypes from "prop-types";
-import {fmconnection} from "../../constants/fmconnection";
+import { fmconnection } from "../../constants/fmconnection";
import Grid from "@material-ui/core/Grid";
import Fab from "@material-ui/core/Fab";
const styles = theme => ({
- root: {
- flexGrow: 1,
- backgroundColor: theme.palette.background.paper,
- },
- card: {
- minWidth: 275,
- backgroundColor: "#dcdcdc",
-
- },
- bullet: {
- display: 'inline-block',
- margin: '0 2px',
- transform: 'scale(0.8)',
- },
- title: {
- fontSize: 14,
-
- },
- pos: {
- marginBottom: 12,
- },
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper
+ },
+ card: {
+ minWidth: 275,
+ backgroundColor: "#dcdcdc"
+ },
+ bullet: {
+ display: "inline-block",
+ margin: "0 2px",
+ transform: "scale(0.8)"
+ },
+ title: {
+ fontSize: 14
+ },
+ pos: {
+ marginBottom: 12
+ }
});
class Product extends Component {
+ constructor(props) {
+ super(props);
+ this.loadProduct = this.loadProduct.bind(this);
+ this.removeProduct = this.removeProduct.bind(this);
+ }
+ state = {
+ productData: [],
+ productMetaDataFileLocation: [],
+ productMetaDataFileType: [],
+ productMetaDataMimeType: [],
+ productReferencesData: [],
+ productId: this.props.productId
+ };
- constructor(props) {
- super(props);
- }
+ componentWillReceiveProps(productId) {
+ // check this.props vs nextProps and setState!
+ // do whatever you want.
+ this.setState({ productId: productId.productId });
+ this.loadProduct();
+ }
- state = {
- productData: [],
- productMetaDataFileLocation:[],
- productMetaDataFileType:[],
- productMetaDataMimeType:[],
- productReferencesData: [],
- productId : this.props.productId,
- };
+ render() {
+ const { classes } = this.props;
+ return (
+ <div className={classes.root}>
+ <Card className={classes.card}>
+ <Grid>
+ <Grid container spacing={24}>
+ <Grid item xs={3}>
+ <CardContent>
+ <Typography variant="h6" color="textPrimary" gutterBottom>
+ <strong>FILE INFO</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ FILE NAME :{" "}
+ <strong>{this.state.productData["name"]}</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ PRODUCT ID :
<strong>{this.state.productData["id"]}</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ STRUCTURE :{" "}
+ <strong>{this.state.productData["structure"]}</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ TRANSFER STATUS :{" "}
+ <strong>{this.state.productData["transferStatus"]}</strong>
+ </Typography>
+ </CardContent>
+ </Grid>
- render() {
+ <Grid item xs={3}>
+ <CardContent>
+ <Typography variant="h6" color="textPrimary" gutterBottom>
+ <strong>METADATA INFO</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ <span style={{ color: "black" }}>FILE LOCATION</span> :{"
"}
+ <strong style={{ fontSize: 12 }}>
+ {this.state.productMetaDataFileLocation["val"]}
+ </strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ PRODUCT TYPE :{" "}
+
<strong>{this.state.productMetaDataFileType["val"]}</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ MIME TYPE :{" "}
+ <strong>{this.state.productMetaDataMimeType[0]}</strong>
+ </Typography>
+ </CardContent>
+ {/*<Button style={{ background: "green" }}>*/}
+ {/* <span style={{ color: "white" }}>View All
Metadata</span>*/}
+ {/*</Button>*/}
+ </Grid>
- const { classes } = this.props;
- return(
- <div className={classes.root}>
- <Card className={classes.card}>
-
- <Grid>
- <Grid container spacing={24}>
- <Grid item xs={3}>
- <CardContent>
- <Typography variant="h4" color="textPrimary" gutterBottom>
- FILE INFO
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- FILE NAME : <strong>{this.state.productData["name"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- PRODUCT ID : <strong>{this.state.productData["id"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- STRUCTURE : <strong>{this.state.productData["structure"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- TRANSFER STATUS :
<strong>{this.state.productData["transferStatus"]}</strong>
- </Typography>
- </CardContent>
- </Grid>
-
- <Grid item xs={3}>
- <CardContent>
- <Typography variant="h4" color="textPrimary" gutterBottom>
- <span style={{color:"black"}}>METADATA INFO</span>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- <span style={{color:"black"}}>FILE LOCATION</span> :
<strong>{this.state.productMetaDataFileLocation["val"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- PRODUCT TYPE :
<strong>{this.state.productMetaDataFileType["val"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- MIME TYPE : <strong>{this.state.productMetaDataMimeType[0]}</strong>
- </Typography>
- </CardContent>
- <Button style={{background:"green"}}><span
style={{color:"white"}}>View All Metadata</span></Button>
- </Grid>
-
- <Grid item xs={3}>
- <CardContent>
- <Typography variant="h4" color="textPrimary" gutterBottom>
- REFERENCE INFO
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- DATA STORE REF LOCATION :
<strong>{this.state.productReferencesData["dataStoreReference"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- FILE SIZE :
<strong>{this.state.productReferencesData["fileSize"]}</strong>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- ORIGINAL REFERENCE :
<strong>{this.state.productReferencesData["originalReference"]}</strong>
- </Typography>
- </CardContent>
- <Button style={{background:"green"}}><span
style={{color:"white"}}>View All References</span></Button>
- </Grid>
-
- <Grid item xs={3}>
- <CardContent>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- <Fab variant="extended" color="primary"
style={{fontSize:20}}>Download File</Fab>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- <Fab variant="extended" color="primary" style={{fontSize:20
,background:"green"}}>View in File Manager</Fab>
- </Typography>
- <Typography variant="h6" color="textPrimary" gutterBottom>
- <Fab variant="extended" color="secondary" style={{fontSize:20}}>Remove
Record</Fab>
- </Typography>
- </CardContent>
- </Grid>
- </Grid>
- </Grid>
+ <Grid item xs={3}>
+ <CardContent>
+ <Typography variant="h6" color="textPrimary" gutterBottom>
+ <strong>REFERENCE INFO</strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ DATA STORE REF LOCATION :{" "}
+ <strong>
+ {this.state.productReferencesData["dataStoreReference"]}
+ </strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ FILE SIZE :{" "}
+ <strong>
+ {this.state.productReferencesData["fileSize"]}
+ </strong>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ ORIGINAL REFERENCE :{" "}
+ <strong>
+ {this.state.productReferencesData["originalReference"]}
+ </strong>
+ </Typography>
+ </CardContent>
+ {/*<Button style={{ background: "green" }}>*/}
+ {/* <span style={{ color: "white" }}>View All
References</span>*/}
+ {/*</Button>*/}
+ </Grid>
+ <Grid item xs={3}>
+ <CardContent>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ <Fab
+ variant="extended"
+ color="primary"
+ style={{ fontSize: 20 }}
+ >
+ Download File
+ </Fab>
+ </Typography>
+ <Typography
+ variant="h6"
+ style={{ fontSize: 15 }}
+ color="textPrimary"
+ gutterBottom
+ >
+ <Fab
+ variant="extended"
+ color="secondary"
+ style={{ fontSize: 20 }}
+ onClick={this.removeProduct}
+ >
+ Remove Record
+ </Fab>
+ </Typography>
+ </CardContent>
+ </Grid>
+ </Grid>
+ </Grid>
</Card>
- </div>
+ </div>
);
- }
+ }
- componentDidMount() {
- console.log(this.state.productId);
- // Make a request for a product with a given ID
- fmconnection.get("/product?productId=" +this.state.productId)
-
- .then(res => {
- this.setState({
- productData:res.data.product,
-
productMetaDataFileLocation:Object.values(res.data.product.metadata)[0][0],
-
productMetaDataFileType:Object.values(res.data.product.metadata)[0][1],
-
productMetaDataMimeType:Object.values(res.data.product.metadata)[0][7]["val"],
-
productReferencesData:res.data.product.references.reference,
- });
- console.log(this.state.productMetaDataFileLocation["val"]);
- console.log(this.state.productMetaDataFileType["val"]);
- console.log(this.state.productMetaDataMimeType[0]);
-
- })
- .catch(err=>{
- console.log(err);
- })
+ removeProduct() {
+ let result = confirm(
+ "Are you Sure to Remove the Product ?" + this.state.productId
+ );
+ if (result == true) {
+ fmconnection
+ .delete("/removeProduct?productId=" + this.state.productId)
+ .then(res => {
+ alert(
+ "Product sucessfully removed productID: " + this.state.productId
+ );
+ this.setState({ productId: "" });
+ });
+ } else {
}
+ }
+
+ loadProduct() {
+ fmconnection
+ .get("/product?productId=" + this.state.productId)
+
+ .then(res => {
+ this.setState({
+ productData: res.data.product,
+ productMetaDataFileLocation: Object.values(
+ res.data.product.metadata
+ )[0][0],
+ productMetaDataFileType: Object.values(
+ res.data.product.metadata
+ )[0][1],
+ productMetaDataMimeType: Object.values(
+ res.data.product.metadata
+ )[0][7]["val"],
+ productReferencesData: res.data.product.references.reference
+ });
+ console.log(this.state.productMetaDataFileLocation["val"]);
+ console.log(this.state.productMetaDataFileType["val"]);
+ console.log(this.state.productMetaDastaMimeType[0]);
+ })
+ .catch(err => {
+ console.log(err);
+ });
+ }
+
+ componentDidMount() {
+ console.log(this.state.productId);
+ // Make a request for a product with a given ID
+ fmconnection
+ .get("/product?productId=" + this.state.productId)
+
+ .then(res => {
+ this.setState({
+ productData: res.data.product,
+ productMetaDataFileLocation: Object.values(
+ res.data.product.metadata
+ )[0][0],
+ productMetaDataFileType: Object.values(
+ res.data.product.metadata
+ )[0][1],
+ productMetaDataMimeType: Object.values(
+ res.data.product.metadata
+ )[0][7]["val"],
+ productReferencesData: res.data.product.references.reference
+ });
+ console.log(this.state.productMetaDataFileLocation["val"]);
+ console.log(this.state.productMetaDataFileType["val"]);
+ console.log(this.state.productMetaDastaMimeType[0]);
+ })
+ .catch(err => {
+ console.log(err);
+ });
+ }
}
Product.propTypes = {
- classes: PropTypes.object.isRequired,
+ classes: PropTypes.object.isRequired
};
export default withStyles(styles)(Product);
diff --git a/react-components/oodt_fm_plugin/src/components/Product/index.js
b/react-components/oodt_fm_plugin/src/components/Product/index.js
index 2e2501e..1289634 100644
--- a/react-components/oodt_fm_plugin/src/components/Product/index.js
+++ b/react-components/oodt_fm_plugin/src/components/Product/index.js
@@ -16,6 +16,6 @@
*/
// Import the Product component from this folder and send it down to
./components/index.js
-import Product from './Product';
+import Product from "./Product";
export default Product;
diff --git
a/react-components/oodt_fm_plugin/src/components/ProductIngest/ProductIngest.js
b/react-components/oodt_fm_plugin/src/components/ProductIngest/ProductIngest.js
new file mode 100644
index 0000000..d9973f9
--- /dev/null
+++
b/react-components/oodt_fm_plugin/src/components/ProductIngest/ProductIngest.js
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import { OutlinedInput, Paper, withStyles } from "@material-ui/core";
+import Typography from "@material-ui/core/Typography";
+import PropTypes from "prop-types";
+import TextField from "@material-ui/core/TextField";
+import Button from "@material-ui/core/Button";
+import { fmconnection } from "../../constants/fmconnection";
+import CircularProgress from "@material-ui/core/CircularProgress";
+
+import FormControl from "@material-ui/core/FormControl";
+import MenuItem from "@material-ui/core/MenuItem";
+import InputLabel from "@material-ui/core/InputLabel";
+import Select from "@material-ui/core/Select";
+import FormHelperText from "@material-ui/core/FormHelperText";
+import Input from "@material-ui/core/Input";
+
+const styles = theme => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ padding: 20
+ },
+ button: {
+ padding: 10,
+ margin: 20
+ },
+ textField: {
+ marginLeft: 2,
+ marginRight: 2
+ },
+ layout: {
+ display: "flex",
+ flexDirection: "row",
+ padding: 0
+ },
+ progress: {
+ margin: 2
+ },
+ formControl: {
+ margin: 1,
+ minWidth: 120
+ }
+});
+
+class ProductIngest extends Component {
+ constructor(props) {
+ super(props);
+ this.handleFile = this.handleFile.bind(this);
+ this.handleProductStructure = this.handleProductStructure.bind(this);
+ this.handleProductType = this.handleProductType.bind(this);
+ this.ingestProduct = this.ingestProduct.bind(this);
+ }
+
+ state = {
+ ingestedFile: null,
+ productId: "",
+ productType: "GenericFile",
+ productStructure: "Flat",
+ isIngested: false,
+ isIngestButtonClicked: false
+ };
+
+ handleFile(e) {
+ let file = e.target.files[0];
+ this.setState({ ingestedFile: file });
+ }
+
+ handleProductStructure(e) {
+ let productStructure = e.target.value;
+ this.setState({ productStructure: productStructure });
+ }
+
+ handleProductType(e) {
+ let productType = e.target.value;
+ this.setState({ productType: productType });
+ console.log(this.state.productType);
+ }
+
+ keyPress(e) {
+ if (e.keyCode === 13) {
+ console.log(e.target.value);
+ this.handleProductStructure();
+ }
+ }
+
+ ingestProduct() {
+ this.setState({ isIngested: false });
+ this.setState({ isIngestButtonClicked: true });
+
+ let product = this.state.ingestedFile;
+ let formData = new FormData();
+ formData.append("productFile", product);
+ fmconnection
+ .post(
+ "productWithFile?productType=" +
+ this.state.productType +
+ "&productStructure=" +
+ this.state.productStructure,
+ formData
+ )
+ .then(result => {
+ console.log(result);
+ this.setState({ productId: result.data });
+ this.setState({ isIngested: true });
+ })
+ .catch(error => {
+ console.log(error);
+ this.setState({ isIngested: false });
+ alert("Product Ingestion Failed : " + error);
+ });
+ }
+
+ render() {
+ const { classes } = this.props;
+
+ return (
+ <Paper className={classes.root}>
+ <Typography variant="h5" component="h3">
+ Product Ingest with Single File
+ </Typography>
+
+ <br />
+
+ <div className={classes.layout}>
+ <form>
+ <FormControl
+ variant="outlined"
+ className={classes.formControl}
+ style={{ width: "200px" }}
+ >
+ <InputLabel htmlFor="outlined-product-Type-simple">
+ Product Type
+ </InputLabel>
+ <Select
+ value={this.state.productType}
+ onChange={this.handleProductType}
+ input={
+ <OutlinedInput
+ labelWidth={100}
+ name="Product Type"
+ id="outlined-product-Type-simple"
+ />
+ }
+ >
+ <MenuItem selected={true} value={"GenericFile"}>
+ GenericFile
+ </MenuItem>
+ <MenuItem value={"LocationAwareProduct"}>
+ LocationAwareProduct
+ </MenuItem>
+ </Select>
+ </FormControl>
+
+ <FormControl
+ variant="outlined"
+ className={classes.formControl}
+ style={{ width: "200px" }}
+ >
+ <InputLabel htmlFor="outlined-product-structure-simple">
+ Product Structure
+ </InputLabel>
+ <Select
+ value={this.state.productStructure}
+ onChange={this.handleProductStructure}
+ input={
+ <OutlinedInput
+ labelWidth={130}
+ name="Product Structure"
+ id="outlined-product-structure-simple"
+ />
+ }
+ >
+ <MenuItem selected={true} value={"Flat"}>
+ Flat
+ </MenuItem>
+ </Select>
+ </FormControl>
+ </form>
+
+ <input
+ className={classes.button}
+ type={"file"}
+ name={"fileToUpload"}
+ id={"fileToUpload"}
+ onChange={e => this.handleFile(e)}
+ />
+
+ <Button
+ variant="contained"
+ color="primary"
+ className={classes.button}
+ onClick={this.ingestProduct}
+ >
+ Ingest Product
+ </Button>
+
+ {this.state.isIngested === false &&
+ this.state.isIngestButtonClicked == true && <CircularProgress />}
+ {this.state.isIngested == true &&
+ alert("Successfully Ingested Product ID :" + this.state.productId)}
+ </div>
+ </Paper>
+ );
+ }
+}
+
+ProductIngest.propTypes = {
+ classes: PropTypes.object.isRequired
+};
+
+export default withStyles(styles)(ProductIngest);
diff --git a/react-components/oodt_fm_plugin/src/components/Product/index.js
b/react-components/oodt_fm_plugin/src/components/ProductIngest/index.js
similarity index 92%
copy from react-components/oodt_fm_plugin/src/components/Product/index.js
copy to react-components/oodt_fm_plugin/src/components/ProductIngest/index.js
index 2e2501e..a9bd7c9 100644
--- a/react-components/oodt_fm_plugin/src/components/Product/index.js
+++ b/react-components/oodt_fm_plugin/src/components/ProductIngest/index.js
@@ -16,6 +16,6 @@
*/
// Import the Product component from this folder and send it down to
./components/index.js
-import Product from './Product';
+import ProductIngest from "./ProductIngest";
-export default Product;
+export default ProductIngest;
diff --git
a/react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/ProductIngestWithMetaFile.js
b/react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/ProductIngestWithMetaFile.js
new file mode 100644
index 0000000..cd4748d
--- /dev/null
+++
b/react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/ProductIngestWithMetaFile.js
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import { Paper, withStyles } from "@material-ui/core";
+import Typography from "@material-ui/core/Typography";
+import PropTypes from "prop-types";
+import Button from "@material-ui/core/Button";
+import { fmconnection } from "../../constants/fmconnection";
+import CircularProgress from "@material-ui/core/CircularProgress";
+
+const styles = theme => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ padding: 20
+ },
+ button: {
+ padding: 10,
+ margin: 20
+ },
+ textField: {
+ marginLeft: 2,
+ marginRight: 2
+ },
+ layout: {
+ display: "flex",
+ flexDirection: "row",
+ padding: 0
+ }
+});
+
+class ProductIngestWithMetaFile extends Component {
+ constructor(props) {
+ super(props);
+ this.handleFile = this.handleFile.bind(this);
+ this.handleMetaFile = this.handleMetaFile.bind(this);
+ this.ingestProduct = this.ingestProduct.bind(this);
+ }
+
+ state = {
+ ingestedFile: null,
+ metaFile: null,
+ productId: "",
+ isIngested: false,
+ isIngestButtonClicked: false
+ };
+
+ handleFile(e) {
+ let file = e.target.files[0];
+ this.setState({ ingestedFile: file });
+ }
+
+ handleMetaFile(e) {
+ let metaFile = e.target.files[0];
+ this.setState({ metaFile: metaFile });
+ }
+
+ ingestProduct() {
+ this.setState({ isIngested: false });
+ this.setState({ isIngestButtonClicked: true });
+
+ let product = this.state.ingestedFile;
+ let metaProduct = this.state.metaFile;
+ let formData = new FormData();
+ formData.append("productFile", product);
+ formData.append("metadataFile", metaProduct);
+ fmconnection
+ .post("productWithMeta", formData)
+ .then(result => {
+ console.log(result);
+ this.setState({ productId: result.data });
+ this.setState({ isIngested: true });
+ alert("Sucessfully Ingested :ProductId " + result.data);
+ })
+ .catch(error => {
+ console.log(error);
+ this.setState({ isIngested: false });
+ alert("Exception Thrown " + error);
+ });
+ }
+
+ render() {
+ const { classes } = this.props;
+
+ return (
+ <Paper className={classes.root}>
+ <Typography variant="h5" component="h3">
+ Product Ingest with Meta File
+ </Typography>
+
+ <div className={classes.layout}>
+ <div>
+ <div>
+ <div>
+ <label>File</label>
+ <input
+ className={classes.button}
+ type={"file"}
+ name={"fileToUpload"}
+ id={"fileToUpload"}
+ onChange={e => this.handleFile(e)}
+ />
+ <label>MetadataFile</label>
+ <input
+ className={classes.button}
+ type={"file"}
+ name={"metaFileToUpload"}
+ id={"metaFileToUpload"}
+ onChange={e => this.handleMetaFile(e)}
+ />
+ </div>
+ </div>
+ </div>
+
+ <Button
+ variant="contained"
+ color="primary"
+ className={classes.button}
+ onClick={this.ingestProduct}
+ >
+ Ingest Product
+ </Button>
+
+ {this.state.isIngested === false &&
+ this.state.isIngestButtonClicked == true && <CircularProgress />}
+ {this.state.isIngested == true &&
+ alert("Sucessfully Ingested :ProductId :" + this.state.productId)}
+ </div>
+ </Paper>
+ );
+ }
+}
+
+ProductIngestWithMetaFile.propTypes = {
+ classes: PropTypes.object.isRequired
+};
+
+export default withStyles(styles)(ProductIngestWithMetaFile);
diff --git a/react-components/oodt_fm_plugin/src/components/Product/index.js
b/react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/index.js
similarity index 88%
copy from react-components/oodt_fm_plugin/src/components/Product/index.js
copy to
react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/index.js
index 2e2501e..3bf6da6 100644
--- a/react-components/oodt_fm_plugin/src/components/Product/index.js
+++
b/react-components/oodt_fm_plugin/src/components/ProductIngestWithMetaFile/index.js
@@ -16,6 +16,6 @@
*/
// Import the Product component from this folder and send it down to
./components/index.js
-import Product from './Product';
+import ProductIngestWithMetaFile from "./ProductIngestWithMetaFile";
-export default Product;
+export default ProductIngestWithMetaFile;
diff --git
a/react-components/oodt_fm_plugin/src/components/ProductList/ProductList.js
b/react-components/oodt_fm_plugin/src/components/ProductList/ProductList.js
new file mode 100644
index 0000000..6ca462a
--- /dev/null
+++ b/react-components/oodt_fm_plugin/src/components/ProductList/ProductList.js
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import { fmconnection } from "../../constants/fmconnection";
+import PropTypes from "prop-types";
+import { OutlinedInput, withStyles } from "@material-ui/core";
+import clsx from "clsx";
+import Button from "@material-ui/core/Button";
+import Grid from "@material-ui/core/Grid";
+import Paper from "@material-ui/core/Paper";
+import SimpleSnackBar from "./SimpleSnackBar";
+import FormControl from "@material-ui/core/FormControl";
+import InputLabel from "@material-ui/core/InputLabel";
+import Select from "@material-ui/core/Select";
+import MenuItem from "@material-ui/core/MenuItem";
+import CircularProgress from "@material-ui/core/CircularProgress";
+import Typography from "@material-ui/core/Typography";
+
+const styles = theme => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper
+ },
+ card: {
+ minWidth: 275,
+ backgroundColor: "#dcdcdc"
+ },
+ bullet: {
+ display: "inline-block",
+ margin: "0 2px",
+ transform: "scale(0.8)"
+ },
+ title: {
+ fontSize: 14
+ },
+ pos: {
+ marginBottom: 12
+ },
+ productcontainer: {
+ display: "flex",
+ flexDirection: "row",
+ padding: 0
+ },
+ paper: {
+ padding: 12,
+ display: "flex",
+ overflow: "auto",
+ flexDirection: "column"
+ },
+ fixedHeight: {
+ height: "auto"
+ },
+ formControl: {
+ margin: 1,
+ minWidth: 120
+ },
+ button: {
+ padding: 10,
+ margin: 20
+ }
+});
+
+class Product extends Component {
+ constructor(props) {
+ super(props);
+ this.setProductTypeName = this.setProductTypeName.bind(this);
+ this.loadProducts = this.loadProducts.bind(this);
+ this.loadNextProducts = this.loadNextProducts.bind(this);
+ this.loadPrevProducts = this.loadPrevProducts.bind(this);
+ this.onClick = this.onClick.bind(this);
+ this.handleProductType = this.handleProductType.bind(this);
+ this.searchProducts = this.searchProducts.bind(this);
+ }
+
+ state = {
+ productData: [],
+ productDetailsArray: [],
+ productFilesArray: [],
+ productFoldersArray: [],
+ productTypeName: "GenericFile",
+ selectedProductId: "",
+ currentProductPage: 1,
+ productTypeArray: [],
+ isSearchButtonClicked: true,
+ isTimedOut: true
+ };
+
+ setProductTypeName(productTypeName) {
+ this.setState({ productTypeName: productTypeName });
+ }
+
+ onClick(message) {
+ this.child.handleClick(message); // do stuff
+ }
+
+ loadProducts() {
+ this.setState({ productData: [] });
+ this.setState({ productDetailsArray: [] });
+ this.setState({ productFilesArray: [] });
+ this.setState({ productFoldersArray: [] });
+ fmconnection
+ .get("/products?productTypeName=" + this.state.productTypeName)
+
+ .then(res => {
+ this.setState({
+ productData: res.data.productPage
+ });
+ this.setState({
+ productDetailsArray: this.state.productData.products.product
+ });
+
+ this.getFiles();
+ this.getFolders();
+
+ // Snackbar for Request Success
+ this.onClick("Request Successful !!");
+ })
+ .catch(error => {
+ if (error.response) {
+ console.log(error.response.data);
+ this.onClick("404 - Couldn't Find Resource");
+ }
+ });
+ }
+
+ loadNextProducts() {
+ this.setState({ currentProductPage: this.state.currentProductPage + 1 });
+ this.setState({ productData: [] });
+ this.setState({ productDetailsArray: [] });
+ this.setState({ productFilesArray: [] });
+ this.setState({ productFoldersArray: [] });
+ fmconnection
+ .get(
+ "/products?productTypeName=" +
+ this.state.productTypeName +
+ "¤tProductPage=" +
+ this.state.currentProductPage
+ )
+
+ .then(res => {
+ this.setState({
+ productData: res.data.productPage
+ });
+ this.setState({
+ productDetailsArray: this.state.productData.products.product
+ });
+
+ this.getFiles();
+ this.getFolders();
+ // Snackbar for Request Success
+ this.onClick("Request Successful !!");
+ })
+ .catch(error => {
+ if (error.response) {
+ console.log(error.response.data);
+ this.onClick("404 - Couldn't Find Resource");
+ }
+ });
+ }
+
+ // Have to Implement
+ loadPrevProducts() {
+ this.setState({ currentProductPage: this.state.currentProductPage - 1 });
+ // this.setState({productData: []});
+ // this.setState({productDetailsArray: []});
+ // this.setState({productFilesArray: []});
+ // this.setState({productFoldersArray: []});
+ // fmconnection.get("/products?productTypeName=" +
this.state.productTypeName+"¤tProductPage="+this.state.currentProductPage)
+ //
+ // .then(res => {
+ // this.setState({
+ // productData: res.data.productPage,
+ // });
+ // this.setState({productDetailsArray:
this.state.productData.products.product});
+ //
+ // this.getFiles();
+ // this.getFolders();
+ // console.log(this.state.productDetailsArray);
+ // })
+ // .catch(err => {
+ // console.log(err);
+ // });
+ }
+
+ getFiles() {
+ let fileArray = [];
+ let fileTypesArray = [];
+ for (let i = 0; i < this.state.productDetailsArray.length; i++) {
+ if (this.state.productDetailsArray[i].structure === "Flat") {
+ fileArray.push(this.state.productDetailsArray[i]);
+ fileTypesArray.push(this.state.productDetailsArray[i].type);
+ }
+ }
+ this.setState({ productFilesArray: fileArray });
+ let uniqueFileTypes = [...new Set(fileTypesArray)];
+ this.setState({ productTypeArray: uniqueFileTypes });
+ }
+
+ getFolders() {
+ let folderArray = [];
+ for (let i = 0; i < this.state.productDetailsArray.length; i++) {
+ if (this.state.productDetailsArray[i].structure === "Hierarchical") {
+ folderArray.push(this.state.productDetailsArray[i]);
+ }
+ }
+ this.setState({ productFoldersArray: folderArray });
+ }
+
+ selectedItem(selectedProductId) {
+ this.setState({ selectedProductId: selectedProductId });
+ this.props.selectedProductId(this.state.selectedProductId);
+ }
+
+ handleProductType(e) {
+ let productTypeName = e.target.value;
+ this.setState({ productTypeName: productTypeName });
+ this.setState({ isSearchButtonClicked: false });
+ this.setState({ isTimedOut: false });
+ }
+
+ searchProducts() {
+ setTimeout(
+ function() {
+ this.setState({ isTimedOut: true });
+ }.bind(this),
+ 3000
+ );
+ this.setState({ isSearchButtonClicked: true });
+ this.loadProducts();
+ }
+ render() {
+ const { classes } = this.props;
+
+ // Mapping Folder-products
+ let listFolderItems = this.state.productFoldersArray.map(product => (
+ <div className={classes.root}>
+ <Grid item xs={12} style={{ padding: 3 }}>
+ <Button variant={"outlined"} color={"inherit"}>
+ {product.name}
+ </Button>
+ </Grid>
+ </div>
+ ));
+
+ // Mapping File-products
+ let listFileItems = this.state.productFilesArray.map(product => (
+ <div className={classes.root}>
+ <Grid item xs={6} style={{ padding: 3 }}>
+ <Button
+ variant={"outlined"}
+ color={"inherit"}
+ onClick={() => {
+ this.selectedItem(product.id);
+ }}
+ >
+ {product.name}
+ </Button>
+ </Grid>
+ </div>
+ ));
+
+ // List Product Types
+ let listProductTypes = this.state.productTypeArray.map(productType => (
+ <MenuItem selected={false} value={productType}>
+ {productType}
+ </MenuItem>
+ ));
+
+ return (
+ <div className={classes.root}>
+ <Paper className={clsx(classes.paper, classes.fixedHeight)}>
+ {/*Success/Error Snackbar*/}
+ <SimpleSnackBar onRef={ref => (this.child = ref)} />
+
+ {/*SearchBar component for productTypeName Search*/}
+ {/*<SearchBar*/}
+ {/* productTypeNameProp={this.setProductTypeName}*/}
+ {/* loadProducts={this.loadProducts}*/}
+ {/*/>*/}
+
+ {/*Product Type Listing Component*/}
+
+ <FormControl variant="outlined" className={classes.formControl}>
+ <InputLabel htmlFor="outlined-product-Type-simple">
+ Product Type
+ </InputLabel>
+ <Select
+ value={this.state.productTypeName}
+ onChange={this.handleProductType}
+ input={
+ <OutlinedInput
+ labelWidth={100}
+ name="Product Type"
+ id="outlined-product-Type-simple"
+ />
+ }
+ style={{ width: "400px" }}
+ >
+ <MenuItem selected={false} value={"Hello"}>
+ Hello
+ </MenuItem>
+ {listProductTypes}
+ </Select>
+ <Button
+ variant="contained"
+ color="primary"
+ className={classes.button}
+ onClick={this.searchProducts}
+ >
+ Search Products
+ </Button>
+ </FormControl>
+
+ {/*Load Folder Products*/}
+ <h4>Folders</h4>
+
+ {this.state.productFoldersArray.length === 0 &&
+ this.state.isSearchButtonClicked === true &&
+ this.state.isTimedOut === false && (
+ <div align={"center"}>
+ <CircularProgress />
+ </div>
+ )}
+
+ {this.state.productFoldersArray.length === 0 &&
+ this.state.isSearchButtonClicked === true &&
+ this.state.isTimedOut === true && (
+ <div align={"center"}>
+ <Typography variant={"h5"}>No Product Files Found
!</Typography>
+ </div>
+ )}
+
+ {this.state.productFoldersArray.length > 0 && (
+ <Grid container spacing={3}>
+ {listFolderItems}
+ </Grid>
+ )}
+
+ {/*Load File Products*/}
+ <h4>Files</h4>
+
+ {this.state.productFilesArray.length === 0 &&
+ this.state.isSearchButtonClicked === true &&
+ this.state.isTimedOut === false && (
+ <div align={"center"}>
+ <CircularProgress />
+ </div>
+ )}
+
+ {this.state.productFilesArray.length === 0 &&
+ this.state.isSearchButtonClicked === true &&
+ this.state.isTimedOut === true && (
+ <div align={"center"}>
+ <Typography variant={"h5"}>No Product Files Found
!</Typography>
+ </div>
+ )}
+
+ {this.state.productFilesArray.length > 0 && (
+ <Grid container spacing={3}>
+ {listFileItems}
+ </Grid>
+ )}
+
+ <Grid item xs={12} md={6}>
+ <Grid container spacing={1} direction="column" alignItems="center">
+ <Grid item>
+ <Button onClick={this.loadPrevProducts}>{"<<"}</Button>
+ <Button>{this.state.currentProductPage}</Button>
+ <Button onClick={this.loadNextProducts}>{">>"}</Button>
+ </Grid>
+ </Grid>
+ </Grid>
+ </Paper>
+ </div>
+ );
+ }
+
+ // Load productType = GenericFile on component Mounting
+ componentDidMount() {
+ this.loadProducts();
+ }
+}
+
+Product.propTypes = {
+ classes: PropTypes.object.isRequired
+};
+
+export default withStyles(styles)(Product);
diff --git
a/react-components/oodt_fm_plugin/src/components/ProductList/SearchBar.js
b/react-components/oodt_fm_plugin/src/components/ProductList/SearchBar.js
new file mode 100644
index 0000000..2cd6180
--- /dev/null
+++ b/react-components/oodt_fm_plugin/src/components/ProductList/SearchBar.js
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import Paper from "@material-ui/core/Paper";
+import InputBase from "@material-ui/core/InputBase";
+import IconButton from "@material-ui/core/IconButton";
+import SearchIcon from "@material-ui/icons/Search";
+import { withStyles } from "@material-ui/core";
+import PropTypes from "prop-types";
+
+const styles = theme => ({
+ root: {
+ padding: "2px 4px",
+ display: "flex",
+ alignItems: "center",
+ width: 400
+ },
+ input: {
+ marginLeft: 8,
+ flex: 1
+ },
+ iconButton: {
+ padding: 10
+ },
+ divider: {
+ width: 1,
+ height: 28,
+ margin: 4
+ }
+});
+
+class SearchBar extends Component {
+ constructor(props) {
+ super(props);
+ this.handleChange = this.handleChange.bind(this);
+ this.keyPress = this.keyPress.bind(this);
+ this.click = this.click.bind(this);
+ }
+
+ state = {
+ productTypeName: ""
+ };
+
+ handleChange(e) {
+ this.setState({ productTypeName: e.target.value });
+ }
+
+ keyPress(e) {
+ if (e.keyCode === 13) {
+ console.log(e.target.value);
+ this.props.productTypeNameProp(this.state.productTypeName);
+ this.click();
+ }
+ }
+
+ click() {
+ this.props.loadProducts();
+ }
+
+ render() {
+ const { classes } = this.props;
+ return (
+ <Paper className={classes.root}>
+ <InputBase
+ className={classes.input}
+ placeholder="Search Products by Product Type Name"
+ inputProps={{ "aria-label": "Search Products" }}
+ onKeyDown={this.keyPress}
+ onChange={this.handleChange}
+ />
+ <IconButton className={classes.iconButton} aria-label="Search">
+ <SearchIcon />
+ </IconButton>
+ </Paper>
+ );
+ }
+}
+
+SearchBar.propTypes = {
+ classes: PropTypes.object.isRequired
+};
+
+export default withStyles(styles)(SearchBar);
diff --git
a/react-components/oodt_fm_plugin/src/components/ProductList/SimpleSnackBar.js
b/react-components/oodt_fm_plugin/src/components/ProductList/SimpleSnackBar.js
new file mode 100644
index 0000000..6db9d8c
--- /dev/null
+++
b/react-components/oodt_fm_plugin/src/components/ProductList/SimpleSnackBar.js
@@ -0,0 +1,82 @@
+import React from "react";
+import Snackbar from "@material-ui/core/Snackbar";
+import IconButton from "@material-ui/core/IconButton";
+import CloseIcon from "@material-ui/icons/Close";
+import PropTypes from "prop-types";
+import { withStyles } from "@material-ui/core";
+
+const styles = theme => ({
+ close: {
+ padding: 20
+ }
+});
+
+class SimpleSnackBar extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ open: false,
+ messa: ""
+ };
+ this.handleClick = this.handleClick.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ }
+
+ handleClick(message) {
+ this.setState({ open: true });
+ this.setState({ messa: message });
+ }
+
+ handleClose(event, reason) {
+ if (reason === "clickaway") {
+ return;
+ }
+
+ this.setState({ open: false });
+ }
+
+ componentDidMount() {
+ this.props.onRef(this);
+ }
+ componentWillUnmount() {
+ this.props.onRef(null);
+ }
+
+ render() {
+ const { classes } = this.props;
+ return (
+ <div>
+ <Snackbar
+ anchorOrigin={{
+ vertical: "bottom",
+ horizontal: "left"
+ }}
+ open={this.state.open}
+ autoHideDuration={6000}
+ onClose={this.handleClose}
+ ContentProps={{
+ "aria-describedby": "message-id"
+ }}
+ message={<span id="message-id">{this.state.messa}</span>}
+ action={[
+ <IconButton
+ key="close"
+ aria-label="Close"
+ color="inherit"
+ className={classes.close}
+ onClick={this.handleClose}
+ >
+ <CloseIcon />
+ </IconButton>
+ ]}
+ />
+ </div>
+ );
+ }
+}
+
+SimpleSnackBar.propTypes = {
+ classes: PropTypes.object.isRequired
+};
+
+export default withStyles(styles)(SimpleSnackBar);
diff --git a/react-components/oodt_fm_plugin/src/components/Product/index.js
b/react-components/oodt_fm_plugin/src/components/ProductList/index.js
similarity index 92%
copy from react-components/oodt_fm_plugin/src/components/Product/index.js
copy to react-components/oodt_fm_plugin/src/components/ProductList/index.js
index 2e2501e..325f50c 100644
--- a/react-components/oodt_fm_plugin/src/components/Product/index.js
+++ b/react-components/oodt_fm_plugin/src/components/ProductList/index.js
@@ -16,6 +16,6 @@
*/
// Import the Product component from this folder and send it down to
./components/index.js
-import Product from './Product';
+import ProductList from "./ProductList";
-export default Product;
+export default ProductList;
diff --git a/react-components/oodt_fm_plugin/src/components/index.js
b/react-components/oodt_fm_plugin/src/components/index.js
index b4c8c0c..a235535 100644
--- a/react-components/oodt_fm_plugin/src/components/index.js
+++ b/react-components/oodt_fm_plugin/src/components/index.js
@@ -15,4 +15,9 @@
* limitations under the License.
*/
-export { default as Product } from './Product';
+export { default as Product } from "./Product";
+export { default as ProductList } from "./ProductList";
+export { default as ProductIngest } from "./ProductIngest";
+export {
+ default as ProductIngestWithMetaFile
+} from "./ProductIngestWithMetaFile";
diff --git a/react-components/oodt_fm_plugin/src/constants/fmconnection.js
b/react-components/oodt_fm_plugin/src/constants/fmconnection.js
index e3597d9..5f8a479 100644
--- a/react-components/oodt_fm_plugin/src/constants/fmconnection.js
+++ b/react-components/oodt_fm_plugin/src/constants/fmconnection.js
@@ -18,5 +18,5 @@
import axios from "axios";
export const fmconnection = axios.create({
- baseURL: 'http://46.4.26.22:8012/fmprod/jaxrs',
+ baseURL: "http://"+window.location.hostname+":8080/cas_product_war/jaxrs/v2"
});
diff --git a/react-components/oodt_fm_plugin/src/index.js
b/react-components/oodt_fm_plugin/src/index.js
index 3dc3ab3..a4cef6b 100644
--- a/react-components/oodt_fm_plugin/src/index.js
+++ b/react-components/oodt_fm_plugin/src/index.js
@@ -17,4 +17,4 @@
// Export all the explicitly exported components, this file will contain our
// components when built by webpack and sent off to the world.
-export * from './components';
\ No newline at end of file
+export * from "./components";
diff --git a/react-components/oodt_opsui_sample_app/README.md
b/react-components/oodt_opsui_sample_app/README.md
new file mode 100644
index 0000000..7aa963c
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/README.md
@@ -0,0 +1,36 @@
+This project was bootstrapped with [Create React
App](https://github.com/facebook/create-react-app).
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm start`
+
+Runs the app in the development mode.<br>
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
+
+The page will reload if you make edits.<br>
+You will also see any lint errors in the console.
+
+### `npm test`
+
+Launches the test runner in the interactive watch mode.<br>
+See the section about [running
tests](https://facebook.github.io/create-react-app/docs/running-tests) for more
information.
+
+### `npm run build`
+
+Builds the app for production to the `build` folder.<br>
+It correctly bundles React in production mode and optimizes the build for the
best performance.
+
+The build is minified and the filenames include the hashes.<br>
+Your app is ready to be deployed!
+
+See the section about
[deployment](https://facebook.github.io/create-react-app/docs/deployment) for
more information.
+
+### Deployment
+
+This section has moved here:
https://facebook.github.io/create-react-app/docs/deployment
+
+### `npm run build` fails to minify
+
+This section has moved here:
https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
diff --git a/react-components/oodt_opsui_sample_app/package.json
b/react-components/oodt_opsui_sample_app/package.json
new file mode 100644
index 0000000..669e93b
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "oodt_opsui_sample_app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "react": "^16.8.6",
+ "react-dom": "^16.8.6",
+ "react-scripts": "3.0.1",
+ "@material-ui/core": "latest",
+ "@material-ui/icons": "^4.2.0",
+ "axios": "^0.19.0",
+ "clsx": "^1.0.4",
+ "react-router-dom": "^5.0.1"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": "react-app"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/react-components/oodt_opsui_sample_app/public/favicon.ico
b/react-components/oodt_opsui_sample_app/public/favicon.ico
new file mode 100644
index 0000000..a11777c
Binary files /dev/null and
b/react-components/oodt_opsui_sample_app/public/favicon.ico differ
diff --git a/react-components/oodt_opsui_sample_app/public/images/oodt_logo.png
b/react-components/oodt_opsui_sample_app/public/images/oodt_logo.png
new file mode 100644
index 0000000..dda5ca2
Binary files /dev/null and
b/react-components/oodt_opsui_sample_app/public/images/oodt_logo.png differ
diff --git a/react-components/oodt_opsui_sample_app/public/index.html
b/react-components/oodt_opsui_sample_app/public/index.html
new file mode 100644
index 0000000..08d1712
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/public/index.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />-->
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+<!-- <meta name="theme-color" content="#000000" />-->
+ <!--
+ manifest.json provides metadata used when your web app is installed on a
+ user's mobile device or desktop. See
https://developers.google.com/web/fundamentals/web-app-manifest/
+ -->
+<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />-->
+ <!--
+ Notice the use of %PUBLIC_URL% in the tags above.
+ It will be replaced with the URL of the `public` folder during the build.
+ Only files inside the `public` folder can be referenced from the HTML.
+
+ Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+ work correctly both with client-side routing and a non-root public URL.
+ Learn how to configure a non-root public URL by running `npm run build`.
+ -->
+ <title>OODT-OPSUI</title>
+ </head>
+ <body>
+ <noscript>You need to enable JavaScript to run this app.</noscript>
+ <div id="root"></div>
+ <!--
+ This HTML file is a template.
+ If you open it directly in the browser, you will see an empty page.
+
+ You can add webfonts, meta tags, or analytics to this file.
+ The build step will place the bundled scripts into the <body> tag.
+
+ To begin the development, run `npm start` or `yarn start`.
+ To create a production bundle, use `npm run build` or `yarn build`.
+ -->
+ </body>
+</html>
diff --git a/react-components/oodt_opsui_sample_app/public/manifest.json
b/react-components/oodt_opsui_sample_app/public/manifest.json
new file mode 100644
index 0000000..1f2f141
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/public/manifest.json
@@ -0,0 +1,15 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/react-components/oodt_opsui_sample_app/src/App.js
b/react-components/oodt_opsui_sample_app/src/App.js
new file mode 100644
index 0000000..282d097
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/App.js
@@ -0,0 +1,141 @@
+import React, { Component } from "react";
+import { BrowserRouter, Switch, Route } from "react-router-dom";
+import {
+ ProductList,
+ Product,
+ ProductIngest,
+ ProductIngestWithMetaFile
+} from "oodt_fm_plugin_sample";
+import OPSUIHome from "./components/OPSUIHome";
+import SearchBar from "./components/SearchBar";
+// import { WorkflowList } from "oodt_wm_plugin_sample";
+import Paper from "@material-ui/core/Paper";
+import Typography from "@material-ui/core/Typography";
+import Switch1 from "@material-ui/core/Switch";
+import axios from "axios";
+
+class MyApp extends Component {
+ constructor(props) {
+ super(props);
+ this.setSelectedProductId = this.setSelectedProductId.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ // this.timeOut = this.timeOut.bind(this);
+ }
+
+ state = {
+ selectedProductId: "",
+ checkedA: false
+ };
+
+ setSelectedProductId(productId) {
+ this.setState({ selectedProductId: productId });
+ console.log(this.state.selectedProductId);
+ }
+
+ componentDidMount() {
+ this.handleChange();
+ // this.timeOut()
+ }
+
+ handleChange(){
+ axios
+ .get("http://"+ window.location.hostname
+":8080/cas_product_war/jaxrs/v2/fmprodstatus")
+ .then(result => {
+ console.log(result.data.FMStatus.serverUp);
+ if (result.data.FMStatus.serverUp) {
+ this.setState({ checkedA: true });
+ }
+ })
+ .catch(error => {});
+ };
+
+ // timeOut() {
+ // setInterval(function () {
+ // axios
+ // .get("http://localhost:8080/cas_product_war/jaxrs/v2/fmprodstatus")
+ // .then(result => {
+ // console.log(result.data.FMStatus.serverUp);
+ // if (result.data.FMStatus.serverUp) {
+ // this.setState({ checkedA: true });
+ // }
+ // })
+ // .catch(error => {});
+ //
+ // }, 10000);
+ // }
+ render() {
+ return (
+ <BrowserRouter>
+ <OPSUIHome>
+ <Switch>
+ <Route
+ exact
+ path={"/"}
+ render={() => (
+ <div>
+ <h1>Dashboard</h1>
+ <Paper
+ style={{
+ flexGrow: 1,
+ backgroundColor: "white",
+ padding: 20
+ }}
+ >
+ <Typography variant="h5" component="h3">
+ File Manager Status
+ <Switch1
+ disabled={true}
+ checked={this.state.checkedA}
+ onChange={this.handleChange}
+ />
+ </Typography>
+ </Paper>
+ </div>
+ )}
+ />
+
+ <Route
+ path={"/products"}
+ render={() => (
+ <ProductList selectedProductId={this.setSelectedProductId} />
+ )}
+ />
+
+ <Route
+ path={"/productIngest"}
+ render={() => (
+ <div>
+ <ProductIngest />
+ <br />
+ <ProductIngestWithMetaFile />
+ </div>
+ )}
+ />
+
+ <Route
+ path={"/product"}
+ render={() => (
+ <div>
+ <SearchBar setSelectedProductId={this.setSelectedProductId}
/>
+ <br />
+ <Product productId={this.state.selectedProductId} />
+ </div>
+ )}
+ />
+
+ <Route
+ path={"/workflows"}
+ render={() => (
+ <div>
+ {/*<WorkflowList />*/}
+ </div>
+ )}
+ />
+ </Switch>
+ </OPSUIHome>
+ </BrowserRouter>
+ );
+ }
+}
+
+export default MyApp;
diff --git a/react-components/oodt_opsui_sample_app/src/App.test.js
b/react-components/oodt_opsui_sample_app/src/App.test.js
new file mode 100644
index 0000000..a754b20
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/App.test.js
@@ -0,0 +1,9 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+it('renders without crashing', () => {
+ const div = document.createElement('div');
+ ReactDOM.render(<App />, div);
+ ReactDOM.unmountComponentAtNode(div);
+});
diff --git a/react-components/oodt_opsui_sample_app/src/components/OPSUIHome.js
b/react-components/oodt_opsui_sample_app/src/components/OPSUIHome.js
new file mode 100644
index 0000000..1eee37b
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/components/OPSUIHome.js
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import clsx from 'clsx';
+import {withStyles} from '@material-ui/core/styles';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Drawer from '@material-ui/core/Drawer';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import IconButton from '@material-ui/core/IconButton';
+import Container from '@material-ui/core/Container';
+import MenuIcon from '@material-ui/icons/Menu';
+import {fmMenuListItems,wmMenuListItems} from './listItems';
+import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
+import {Link} from "react-router-dom";
+
+import ListItem from "@material-ui/core/ListItem";
+import ListItemIcon from "@material-ui/core/ListItemIcon";
+import DashboardIcon from "@material-ui/icons/Dashboard";
+import ListItemText from "@material-ui/core/ListItemText";
+import PropTypes from "prop-types";
+
+
+const drawerWidth = 240;
+
+const styles = (theme => ({
+ root: {
+ display: 'flex',
+ },
+ toolbar: {
+ paddingRight: 24, // keep right padding when drawer closed
+ },
+ toolbarIcon: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ padding: '0 8px',
+ ...theme.mixins.toolbar,
+ },
+ appBar: {
+ zIndex: theme.zIndex.drawer + 1,
+ transition: theme.transitions.create(['width', 'margin'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ },
+ appBarShift: {
+ marginLeft: drawerWidth,
+ width: `calc(100% - ${drawerWidth}px)`,
+ transition: theme.transitions.create(['width', 'margin'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ },
+ menuButton: {
+ marginRight: 36,
+ },
+ menuButtonHidden: {
+ display: 'none',
+ },
+ title: {
+ flexGrow: 1,
+ },
+ drawerPaper: {
+ position: 'relative',
+ whiteSpace: 'nowrap',
+ width: drawerWidth,
+ transition: theme.transitions.create('width', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ },
+ drawerPaperClose: {
+ overflowX: 'hidden',
+ transition: theme.transitions.create('width', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ width: theme.spacing(7),
+ [theme.breakpoints.up('sm')]: {
+ width: theme.spacing(9),
+ },
+ },
+ appBarSpacer: theme.mixins.toolbar,
+ content: {
+ flexGrow: 1,
+ height: '100vh',
+ overflow: 'auto',
+ },
+ container: {
+ paddingTop: theme.spacing(4),
+ paddingBottom: theme.spacing(4),
+ },
+ paper: {
+ padding: theme.spacing(2),
+ display: 'flex',
+ overflow: 'auto',
+ flexDirection: 'column',
+ },
+ fixedHeight: {
+ height: 'auto',
+ },
+ logo: {
+ color: 'blue',
+ textAlign: 'center'
+ },
+ button: {
+ color: 'yellow',
+ },
+}));
+
+
+class OPSUIHome extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ open: true,
+ selectedProductId: '',
+ };
+ this.setSelectedProductId=this.setSelectedProductId.bind(this);
+ }
+
+ handleDrawerOpen = () => {
+ this.setState({open: true});
+ };
+
+ handleDrawerClose = () => {
+ this.setState({open: false});
+ };
+
+
+ testFunction = () => {
+ console.log("Hello");
+ };
+
+
+ setSelectedProductId(productId) {
+ this.setState({selectedProductId: productId});
+ };
+
+
+ render() {
+ const {classes} = this.props;
+
+ return (
+ <div className={classes.root}>
+ <CssBaseline/>
+ <AppBar position="absolute" className={clsx(classes.appBar,
this.state.open && classes.appBarShift)}>
+ <Toolbar className={classes.toolbar}>
+ <IconButton
+ edge="start"
+ color="inherit"
+ aria-label="Open drawer"
+ onClick={this.handleDrawerOpen}
+ className={clsx(classes.menuButton,
this.state.open && classes.menuButtonHidden)}
+ >
+ <MenuIcon/>
+ </IconButton>
+ <Typography component="h1" variant="h6"
color="inherit" noWrap className={classes.title}>
+ Apache OODT - OPSUI
+ </Typography>
+
+ </Toolbar>
+ </AppBar>
+ <Drawer variant="permanent" className={classes.logo}
+ classes={{paper: clsx(classes.drawerPaper,
!this.state.open && classes.drawerPaperClose),}}
+ open={this.state.open}>
+ <div>
+ <IconButton onClick={this.handleDrawerClose}>
+ <div>
+ <img src="/images/oodt_logo.png" alt="Apache
OODT Logo" width="110px"/>
+ </div>
+ <ChevronLeftIcon/>
+ </IconButton>
+
+ </div>
+
+ {/*Main Menu List*/}
+ {/*<List>{mainListItems}</List>*/}
+ <List>
+ <div>
+
+
+ {/*Status of OPSUI*/}
+ <ListItem button component={Link} to={"/"} >
+ {/*onClick={this.testFunction.bind(this)}*/}
+ <ListItemIcon>
+ <DashboardIcon/>
+ </ListItemIcon>
+ <ListItemText primary="Dashboard"/>
+ </ListItem>
+ </div>
+ </List>
+
+ <Divider/>
+
+
+ {/*FileManager Menu List*/}
+ <List>{fmMenuListItems}</List>
+ <Divider/>
+
+ {/*Workflow Manager Menu List*/}
+ <List>{wmMenuListItems}</List>
+
+ </Drawer>
+ <main className={classes.content}>
+ <div className={classes.appBarSpacer}/>
+ <Container maxWidth="lg" className={classes.container}>
+ {this.props.children}
+
+ </Container>
+
+ </main>
+
+ </div>
+ );
+ }
+}
+
+
+OPSUIHome.propTypes = {
+ classes: PropTypes.object.isRequired,
+};
+
+export default withStyles(styles)(OPSUIHome);
\ No newline at end of file
diff --git a/react-components/oodt_opsui_sample_app/src/components/SearchBar.js
b/react-components/oodt_opsui_sample_app/src/components/SearchBar.js
new file mode 100644
index 0000000..4a417b3
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/components/SearchBar.js
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, {Component} from 'react';
+import Paper from '@material-ui/core/Paper';
+import InputBase from '@material-ui/core/InputBase';
+import IconButton from '@material-ui/core/IconButton';
+import SearchIcon from '@material-ui/icons/Search';
+import {withStyles} from "@material-ui/core";
+import {PropTypes} from "prop-types";
+
+
+const styles = theme => ({
+ root: {
+ padding: '2px 4px',
+ display: 'flex',
+ alignItems: 'center',
+ width: 400,
+ },
+ input: {
+ marginLeft: 8,
+ flex: 1,
+ },
+ iconButton: {
+ padding: 10,
+ },
+ divider: {
+ width: 1,
+ height: 28,
+ margin: 4,
+ },
+});
+
+class SearchBar extends Component {
+
+ constructor(props) {
+ super(props);
+ this.handleChange = this.handleChange.bind(this);
+ this.keyPress = this.keyPress.bind(this);
+ // this.click = this.click.bind(this);
+ }
+
+ state = {
+ selectedProductId: '',
+ };
+
+ handleChange(e) {
+ this.setState({ selectedProductId: e.target.value });
+ }
+
+ keyPress(e){
+ if(e.keyCode === 13){
+ console.log(e.target.value);
+ this.props.setSelectedProductId(this.state.selectedProductId);
+ // this.click();
+ }
+ }
+
+ // click() {
+ // this.props.loadProducts();
+ // }
+
+ render(){
+ const { classes } = this.props;
+ return (
+ <Paper className={classes.root}>
+ <InputBase
+ className={classes.input}
+ placeholder="Search Products by Product Id"
+ inputProps={{ 'aria-label': 'Search Products' }}
+ onKeyDown={this.keyPress} onChange={this.handleChange}
+ />
+ <IconButton className={classes.iconButton} aria-label="Search"
>
+ <SearchIcon />
+ </IconButton>
+ </Paper>
+ );
+ }
+
+
+}
+
+
+SearchBar.propTypes = {
+ classes: PropTypes.object.isRequired,
+};
+
+export default withStyles(styles)(SearchBar);
diff --git a/react-components/oodt_opsui_sample_app/src/components/listItems.js
b/react-components/oodt_opsui_sample_app/src/components/listItems.js
new file mode 100644
index 0000000..1ee820b
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/components/listItems.js
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import DashboardIcon from '@material-ui/icons/Dashboard';
+import NoteAddIcon from '@material-ui/icons/NoteAdd';
+import StorageIcon from '@material-ui/icons/Storage';
+import FindInPage from '@material-ui/icons/FindInPage';
+import {Link} from "react-router-dom";
+
+
+
+export const mainListItems = (
+
+
+
+ <div>
+ {/*Status of OPSUI*/}
+ <ListItem button>
+ <ListItemIcon>
+ <DashboardIcon />
+ </ListItemIcon>
+ <ListItemText primary="Dashboard" />
+ </ListItem>
+ </div>
+);
+
+
+
+export const fmMenuListItems = (
+ <div>
+
+ <ListSubheader>File Manager</ListSubheader>
+
+ {/*Product Ingesting*/}
+ <ListItem button component={Link} to={"/productIngest"}>
+ <ListItemIcon>
+ <NoteAddIcon/>
+ </ListItemIcon>
+ <ListItemText primary="Product Ingest" />
+ </ListItem>
+
+ {/*Product Browser*/}
+ <ListItem button component={Link} to={"/products"}>
+ <ListItemIcon>
+ <StorageIcon />
+ </ListItemIcon>
+ <ListItemText primary="Product Browser" />
+ </ListItem>
+
+ {/*Product Search*/}
+ <ListItem button component={Link} to={"/product"}>
+ <ListItemIcon>
+ <FindInPage/>
+ </ListItemIcon>
+ <ListItemText primary="Product Search" />
+ </ListItem>
+
+ </div>
+
+);
+
+
+export const wmMenuListItems = (
+ <div>
+ <ListSubheader>WorkFlow Manager</ListSubheader>
+
+ {/*Workflow Browser*/}
+ <ListItem button component={Link} to={"/workflows"}>
+ <ListItemIcon>
+ <StorageIcon />
+ </ListItemIcon>
+ <ListItemText primary="Workflow Browser" />
+ </ListItem>
+ </div>
+);
\ No newline at end of file
diff --git a/react-components/oodt_opsui_sample_app/src/index.css
b/react-components/oodt_opsui_sample_app/src/index.css
new file mode 100644
index 0000000..4a1df4d
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/index.css
@@ -0,0 +1,13 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
+ monospace;
+}
diff --git a/react-components/oodt_opsui_sample_app/src/index.js
b/react-components/oodt_opsui_sample_app/src/index.js
new file mode 100644
index 0000000..8110e69
--- /dev/null
+++ b/react-components/oodt_opsui_sample_app/src/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+// import * as serviceWorker from './serviceWorker';
+
+ReactDOM.render(<App />, document.getElementById('root'));
+
+// If you want your app to work offline and load faster, you can change
+// unregister() to register() below. Note this comes with some pitfalls.
+// Learn more about service workers: https://bit.ly/CRA-PWA
+// serviceWorker.unregister();
diff --git
a/webapp/fmprod/src/main/java/org/apache/oodt/cas/product/jaxrs/enums/ErrorType.java
b/webapp/fmprod/src/main/java/org/apache/oodt/cas/product/jaxrs/enums/ErrorType.java
deleted file mode 100644
index 2a2339b..0000000
---
a/webapp/fmprod/src/main/java/org/apache/oodt/cas/product/jaxrs/enums/ErrorType.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.oodt.cas.product.jaxrs.enums;
-
-/**
- * This is the Enumeration file for storing HTTP Exception types. Use these
constants instead of
- * hardcoding errors in REST API implementations
- *
- * @author ngimhana (Nadeeshan Gimhana)
- */
-public enum ErrorType {
- BAD_REQUEST_EXCEPTION("Malformed message"),
- BAD_REQUEST_EXCEPTION_REFERENCE_RESOURCE(
- "This URL requires a productId query parameter with a product ID value,"
- + " e.g. /reference?productId=1787a257-df87-11e2-8a2d-e3f6264e86c5"),
-
- BAD_REQUEST_EXCEPTION_PRODUCT_RESOURCE(
- "Failed to load resource: the server responded with a status of 400"),
- BAD_REQUEST_EXCEPTION_DATASET_RESOURCE(
- "This URL requires a productTypeId query parameter and either a "
- + "product type ID value or 'ALL' for all product types"),
-
- BAD_REQUEST_EXCEPTION_TRANSFER_RESOURCE(
- "This URL requires a dataStoreRef query parameter "
- + "and a data store reference value, e.g.
/transfer?dataStoreRef=file:/repository/test.txt/test.txt"),
-
- INTERNAL_SERVER_ERROR("General Server Error"),
-
- NOT_FOUND_EXCEPTION("Couldn’t find resource"),
- NOT_FOUND_EXCEPTION_TRANSFER_RESOURCE(
- "Unable to find a current file transfer status for data store reference:
"),
-
- CAS_PRODUCT_EXCEPTION_FILEMGR_CLIENT_UNAVILABLE(
- "Unable to get the file manager client from the servlet context."),
- CAS_PRODUCT_EXCEPTION_FILEMGR_WORKING_DIR_UNAVILABLE(
- "Unable to get the file manager's" + " working directory from the
servlet context.");
-
- private String errorType;
-
- ErrorType(String errorType) {
- this.errorType = errorType;
- }
-
- /** @return the errorType */
- public String getErrorType() {
- return errorType;
- }
-
- /** @param errorType the errorType to set */
- public void setErrorType(String errorType) {
- this.errorType = errorType;
- }
-}