diff --git a/src/components/query/QueryIVOARegistry.js b/src/components/query/QueryIVOARegistry.js index 9624ea3b8fe00e080fb103ad0786ef16631116d7..c917868b127698a4c76c726b6be3baaab7e0f346 100644 --- a/src/components/query/QueryIVOARegistry.js +++ b/src/components/query/QueryIVOARegistry.js @@ -1,30 +1,24 @@ -import React, { useState, useContext, useEffect } from "react"; -import { useHistory, useParams } from "react-router-dom"; import axios from "axios"; -import { Container, Button, Row, Col, Form as RBForm } from "react-bootstrap"; +import React, { useContext, useEffect, useState } from "react"; +import { Button, Col, Container, Row } from "react-bootstrap"; import Form from "react-jsonschema-form"; +import "../../assets/IVOA.css"; import { GlobalContext } from "../../contexts/GlobalContext"; +import { IVOAContext } from "../../contexts/IVOAContext"; import { QueryContext } from "../../contexts/QueryContext"; -import QueryResults from "../services/query_results/QueryResults"; import parseQueryForm from "../../utils/form/parseQueryForm"; -import { IVOAContext } from "../../contexts/IVOAContext"; import parseVOServiceForm from "../../utils/form/parseVOServiceForm"; -import VOServiceResults from "../services/query_results/IVOAResults"; import { getQueryIcon } from "../../utils/styling"; -import "../../assets/IVOA.css"; import LoadingSpinner from "../LoadingSpinner"; -import JSONTree from 'react-json-tree' -import { Map } from 'immutable' +import QueryResults from "../services/query_results/QueryResults"; +import RunQueryComponent from "./ivoa/RunQuery"; + export default function QueryIVOARegistry() { - // queryMap is a map of dictionaries, where each dictionary consists of - // {"catalog": "catalogname", - // "catalogquery": "querystring", - // "status": "fetching|fechted", - // "results": null} - const {setConfigName, defaultConf, queryMap, formData, setFormData, page, setPage, setDPLevel, setCollection} = useContext(QueryContext); + + const { setConfigName, defaultConf, queryMap, formData, setFormData, page } = useContext(QueryContext); const { api_host } = useContext( GlobalContext ); @@ -32,64 +26,61 @@ export default function QueryIVOARegistry() { IVOAContext ); const [config, setConfig] = useState(); - const [url, setURL] = useState(""); const [dplevel] = useState(); const [collection] = useState(); - const [configName] = useState(defaultConf); - const [preview, setPreview] = useState(false); - const [ds9, setDS9] = useState(false); - const {loginAgain } = useContext(GlobalContext); - const [categories, setCategories] = useState([]); - const history = useHistory(); + const [metadata, setMetadata] = React.useState({}); const [loading, setLoading] = React.useState(true); - const { uri } = useParams(); - if (config==null){ + if (config == null) { fetchConfiguration(defaultConf); } function fetchConfiguration(configName) { - let configNameString = configName; - if (configName) { - configNameString = `?name=${configName}`; - } + let configNameString = configName; + if (configName) { + configNameString = `?name=${configName}`; + } - axios - .get(api_host + "query/configuration" + configNameString) - .then((response) => { - let props = response.data["configuration"].query_schema.properties; + axios + .get(api_host + "query/configuration" + configNameString) + .then((response) => { + let props = response.data["configuration"].query_schema.properties; - Object.keys(props).map((key) => { - if (key === "collection" && collection) { - props[key]["default"] = collection; - } - if (key === "level" && dplevel) { - props[key]["default"] = dplevel; - } - return null; - }); - setConfig(response.data["configuration"]); - }).catch((error) => { - let description = ". Configuration not loaded. Is ESAP-API online? " + api_host - console.log(error.toString() + description) - // alert(description) - //const loginUrl = api_host + "oidc/authenticate" - // window.location = loginUrl - // loginAgain() - }); + Object.keys(props).map((key) => { + if (key === "collection" && collection) { + props[key]["default"] = collection; + } + if (key === "level" && dplevel) { + props[key]["default"] = dplevel; + } + return null; + }); + setConfig(response.data["configuration"]); + }).catch((error) => { + let description = ". Configuration not loaded. Is ESAP-API online? " + api_host + console.log(error.toString() + description) + // alert(description) + //const loginUrl = api_host + "oidc/authenticate" + // window.location = loginUrl + // loginAgain() + }); } // set ConfigName for archive useEffect(() => { - setConfigName("esap_ivoa"); + + setConfigName("esap_ivoa"); + + return () => { queryMap.clear(); setFormData(); setConfigName(defaultConf); }; + }, []); // load the GUI for this configuration @@ -124,17 +115,17 @@ export default function QueryIVOARegistry() { axios .get(url) .then((queryResponse) => { - if(queryStep === "run-query") { - let vo_table_schema = queryResponse.data.results ? queryResponse.data.results[0] : null; - let status = queryResponse.data.results ? "fetched" : "error"; - queryMap.set(query.catalog, { - catalog: query.catalog, - service_type: query.service_type, - vo_table_schema: vo_table_schema, - esapquery: query.esapquery, - status: status, - results: queryResponse.data, - }); + if (queryStep === "run-query") { + let vo_table_schema = queryResponse.data.results ? queryResponse.data.results[0] : null; + let status = queryResponse.data.results ? "fetched" : "error"; + queryMap.set(query.catalog, { + catalog: query.catalog, + service_type: query.service_type, + vo_table_schema: vo_table_schema, + esapquery: query.esapquery, + status: status, + results: queryResponse.data, + }); } else { @@ -144,13 +135,14 @@ export default function QueryIVOARegistry() { esapquery: query.esapquery, status: "fetched", results: queryResponse.data, - })}; + }) + }; }) .catch((error) => { queryMap.set(query.catalog, { catalog: query.catalog, service_type: query.service_type, - vo_table_schema:"", + vo_table_schema: "", esapquery: query.esapquery, status: "error", results: [error.message], @@ -160,26 +152,7 @@ export default function QueryIVOARegistry() { }, [formData, page, regPage]); - const theme = { - scheme: 'monokai', - author: 'wimer hazenberg (http://www.monokai.nl)', - base00: '#272822', - base01: '#383830', - base02: '#49483e', - base03: '#75715e', - base04: '#a59f85', - base05: '#f8f8f2', - base06: '#f5f4f1', - base07: '#f9f8f5', - base08: '#f92672', - base09: '#fd971f', - base0A: '#f4bf75', - base0B: '#a6e22e', - base0C: '#a1efe4', - base0D: '#66d9ef', - base0E: '#ae81ff', - base0F: '#cc6633', - }; + function formTemplate({ TitleField, properties, title, description }) { @@ -187,7 +160,7 @@ export default function QueryIVOARegistry() { <div> <TitleField title={title} /> <div className="row"> - {properties.filter(property => property.content.props.uiSchema["ui:widget"]!="hidden").map((prop) => ( + {properties.filter(property => property.content.props.uiSchema["ui:widget"] != "hidden").map((prop) => ( <div className="col-lg-2 col-md-4 col-sm-6 col-xs-12" key={prop.content.key} @@ -203,120 +176,29 @@ export default function QueryIVOARegistry() { let uiSchemaProp = {} - if (config){ + if (config) { uiSchemaProp = config.ui_schema ? { uiSchema: config.ui_schema } : {}; } else { uiSchemaProp = {}; } if (queryStep === "run-query") { - - if (config){ - uiSchemaProp.uiSchema = { - adql_query: { "ui:widget": "textarea" }, - keyword: { "ui:widget": "hidden" }, - service_type: { "ui:widget": "hidden" }, - catalog: { "ui:widget": "hidden" }, - tap_schema: { "ui:widget": "hidden" }, - waveband: { "ui:widget": "hidden" }, - }; - - if (selectedServices && loading){ - let catalogues = {}; - let counter = 1; - let selectedServicesLength = selectedServices.length; - selectedServices.forEach((access_url) => { - - let selectedService = access_url; - let catalogueTitle = access_url; - let tf_url = api_host + "query/get-tables-fields/?dataset_uri=vo_reg&access_url=" + selectedService; - axios - .get(tf_url) - .then((tfResponse) => { - let jsond = tfResponse.data.results; - let schemas = {}; - Object.keys(jsond).forEach(function(key) { - let table = {}; - let fields_updated = {}; - let metadata_couple = jsond[key].table_name.split(/[.]+/); - let schemaname = metadata_couple[0]; - let tablename = metadata_couple[1]; - table["fields"] = {}; - table["type"] = "table"; - table["full_name"] = jsond[key]["table_name"]; - let fields = jsond[key].fields; - Object.keys(fields).forEach(function(fieldkey) { - let fieldname = fields[fieldkey].name; - table["fields"][fieldname] = fields[fieldkey]; - }); - - if (!(schemaname in schemas)) { - schemas[schemaname] = {}; - } - schemas[schemaname][tablename] = table; - }); - - catalogues[catalogueTitle] = schemas; - let metanew = metadata; - metanew[catalogueTitle] = schemas; - setMetadata(metanew); - if (counter >= selectedServicesLength){ - setLoading(false); - } - counter += 1; - - }).catch(error => { - console.log(error); - }); - - }); - - } - return ( - <Container fluid> - <Form - schema={config.query_schema} - ObjectFieldTemplate={formTemplate} - formData={formData} - onSubmit={({ formData }) => setFormData(formData)} - {...uiSchemaProp} - > - <label className="control-label">Selected Services</label> - <RBForm.Control as="select" className="selectedServices" multiple> - {selectedServices.map((service) => { - return <option key="{service}">{service}</option>; - })} - </RBForm.Control> - - - <div className="metadata-tree"> - <label className="control-label">Service Metadata</label> - - { !loading ? - <JSONTree data={metadata} theme={theme} invertTheme={true} hideRoot={true} /> - : <LoadingSpinner/> } - - </div> - - <div> - <Button className="mt-3" type="submit"> - Query VO Resource - </Button> - </div> - </Form> - {selectedServices.map((service) => { - const details = queryMap.get(service); - return ( - <div key="{service}" className="mt-3"> - <VOServiceResults key="{service}" catalog={service} /> - </div> - ); - })} - </Container> - ); - } + return RunQueryComponent({ + config: config, + uiSchemaProp: uiSchemaProp, + selectedServices: selectedServices, + api_host: api_host, + loading: loading, + setLoading: setLoading, + metadata: metadata, + setMetadata: setMetadata, + formTemplate: formTemplate, + formData: formData, + setFormData: setFormData, + queryMap: queryMap + }); } else { - if (config){ + if (config) { return ( <Container fluid> <Form @@ -367,8 +249,8 @@ export default function QueryIVOARegistry() { })} </Container> ); - } else { - return (<LoadingSpinner />); + } else { + return (<LoadingSpinner />); } } } diff --git a/src/components/query/ivoa/RunQuery.js b/src/components/query/ivoa/RunQuery.js new file mode 100644 index 0000000000000000000000000000000000000000..4d4a836aadcd9893fd0f546de8266f293a151c84 --- /dev/null +++ b/src/components/query/ivoa/RunQuery.js @@ -0,0 +1,144 @@ +import axios from "axios"; +import React from "react"; +import { Button, Container, Form as RBForm } from "react-bootstrap"; +import JSONTree from "react-json-tree"; +import Form from "react-jsonschema-form"; +import LoadingSpinner from "../../LoadingSpinner"; +import VOServiceResults from "../../services/query_results/IVOAResults"; + +// Color theme for JSON Tree +const COLOR_THEME = { + scheme: 'monokai', + author: 'wimer hazenberg (http://www.monokai.nl)', + base00: '#272822', + base01: '#383830', + base02: '#49483e', + base03: '#75715e', + base04: '#a59f85', + base05: '#f8f8f2', + base06: '#f5f4f1', + base07: '#f9f8f5', + base08: '#f92672', + base09: '#fd971f', + base0A: '#f4bf75', + base0B: '#a6e22e', + base0C: '#a1efe4', + base0D: '#66d9ef', + base0E: '#ae81ff', + base0F: '#cc6633', +}; + +function RunQueryComponent(props) { + + const { config, uiSchemaProp, selectedServices, loading, + api_host, metadata, setMetadata, setLoading, formTemplate, formData, setFormData, queryMap } = props; + + + if (config) { + uiSchemaProp.uiSchema = { + adql_query: { "ui:widget": "textarea" }, + keyword: { "ui:widget": "hidden" }, + service_type: { "ui:widget": "hidden" }, + catalog: { "ui:widget": "hidden" }, + tap_schema: { "ui:widget": "hidden" }, + waveband: { "ui:widget": "hidden" }, + }; + + if (selectedServices && loading) { + let catalogues = {}; + let counter = 1; + let selectedServicesLength = selectedServices.length; + selectedServices.forEach((access_url) => { + + let selectedService = access_url; + let catalogueTitle = access_url; + let tf_url = api_host + "query/get-tables-fields/?dataset_uri=vo_reg&access_url=" + selectedService; + axios + .get(tf_url) + .then((tfResponse) => { + let jsond = tfResponse.data.results; + let schemas = {}; + Object.keys(jsond).forEach(function (key) { + let table = {}; + let fields_updated = {}; + let metadata_couple = jsond[key].table_name.split(/[.]+/); + let schemaname = metadata_couple[0]; + let tablename = metadata_couple[1]; + table["fields"] = {}; + table["type"] = "table"; + table["full_name"] = jsond[key]["table_name"]; + let fields = jsond[key].fields; + Object.keys(fields).forEach(function (fieldkey) { + let fieldname = fields[fieldkey].name; + table["fields"][fieldname] = fields[fieldkey]; + }); + + if (!(schemaname in schemas)) { + schemas[schemaname] = {}; + } + schemas[schemaname][tablename] = table; + }); + + catalogues[catalogueTitle] = schemas; + let metanew = metadata; + metanew[catalogueTitle] = schemas; + setMetadata(metanew); + if (counter >= selectedServicesLength) { + setLoading(false); + } + counter += 1; + + }).catch(error => { + console.log(error); + }); + + }); + + } + return ( + <Container fluid> + <Form + schema={config.query_schema} + ObjectFieldTemplate={formTemplate} + formData={formData} + onSubmit={({ formData }) => setFormData(formData)} + {...uiSchemaProp} + > + <label className="control-label">Selected Services</label> + <RBForm.Control as="select" className="selectedServices" multiple> + {selectedServices.map((service) => { + return <option key="{service}">{service}</option>; + })} + </RBForm.Control> + + + <div className="metadata-tree"> + <label className="control-label">Service Metadata</label> + + {!loading ? + <JSONTree data={metadata} theme={COLOR_THEME} invertTheme={true} hideRoot={true} /> + : <LoadingSpinner />} + + </div> + + <div> + <Button className="mt-3" type="submit"> + Query VO Resource + </Button> + </div> + </Form> + {selectedServices.map((service) => { + const details = queryMap.get(service); + return ( + <div key="{service}" className="mt-3"> + <VOServiceResults key="{service}" catalog={service} /> + </div> + ); + })} + </Container> + ); + } + +} + +export default RunQueryComponent;