Skip to content
Snippets Groups Projects
QueryIVOARegistry.js 11.9 KiB
Newer Older
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 Form from "react-jsonschema-form";
import { GlobalContext } from "../../contexts/GlobalContext";
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'



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 { api_host } = useContext(
    GlobalContext
  );
  const { selectedServices, setSelectedServices, queryStep, setQueryStep, regPage } = useContext(
  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){
    fetchConfiguration(defaultConf);
  }

  function fetchConfiguration(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;

                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");
    return () => {
      setConfigName(defaultConf);
  // load the GUI for this configuration
  useEffect(() => {
    if (!formData) return;
    const gui = config.query_schema.name;
    let queries = [];

    if (queryStep === "run-query") {
      selectedServices.forEach((access_url) => {
        queries = [
          ...queries,
          ...parseVOServiceForm(formData, access_url, page),
        ];
      queries = parseQueryForm(gui, formData, regPage);
    queryMap.clear();
    queries.forEach((query) => {
      queryMap.set(query.catalog, {
        catalog: query.catalog,
        service_type: query.service_type,
        esapquery: query.esapquery,
        status: "fetching",
        results: null,
      });
      let url = api_host + "query/" + query.esapquery;
      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,
          }
          else {
            queryMap.set(query.catalog, {
              catalog: query.catalog,
              service_type: query.service_type,
              esapquery: query.esapquery,
              status: "fetched",
              results: queryResponse.data,
          queryMap.set(query.catalog, {
            catalog: query.catalog,
            service_type: query.service_type,
            vo_table_schema:"",
            esapquery: query.esapquery,
            status: "error",
            results: [error.message],

  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 }) {
    return (
      <div>
        <TitleField title={title} />
        <div className="row">
          {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}
            >
              {prop.content}
            </div>
          ))}
        </div>
        {description}
      </div>
    );
  }

  let uiSchemaProp = {}
  if (config){
    uiSchemaProp = config.ui_schema ? { uiSchema: config.ui_schema } : {};
  } else {
    uiSchemaProp = {};
  }
    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} />
          })}
        </Container>
      );
    }
  } else {
    if (config){
      return (
        <Container fluid>
          <Form
            schema={config.query_schema}
            ObjectFieldTemplate={formTemplate}
            formData={formData}
            onSubmit={({ formData }) => setFormData(formData)}
            {...uiSchemaProp}
          >
            <div>
              <Button type="submit">{getQueryIcon()} Query VO Registry</Button>
          </Form>
          {Array.from(queryMap.keys()).map((catalog) => {
            const details = queryMap.get(catalog);
            // let catalogName =
            //   config.query_schema.properties.catalog.enumNames[
            //     config.query_schema.properties.catalog.enum.findIndex(
            //       (name) => name === catalog
            //     )
            //   ];
            return (
              <div key={catalog} className="mt-3">
                <Row>
                  <Col>
                    <h4>List of VO Resources</h4>
                  </Col>
                  <Col>
                    {selectedServices.length === 0 ? (
                      <></>
                    ) : (
                      <Button
                        type="submit"
                        onClick={() => {
                          setQueryStep("run-query");
                        }}
                      >
                        Query selected VO Resources
                      </Button>
                    )}
                  </Col>
                </Row>
                <div className="mt-3">
                  <QueryResults catalog={catalog} />
                </div>
              </div>
            );
          })}
        </Container>
      );
     } else {
        return (<LoadingSpinner />);
    }