diff --git a/src/components/Interactive.js b/src/components/Interactive.js index 9ba219db463f3dc15c3ff14fea76442992a3a822..b3508f3beaf43e391098e289588ba751960d6a54 100644 --- a/src/components/Interactive.js +++ b/src/components/Interactive.js @@ -2,5 +2,16 @@ import React from "react"; import { Alert } from "react-bootstrap"; export default function Interactive() { - return <Alert variant="info">This service is under development!</Alert>; + return ( + <Alert variant="warning"> + <p>You will leave ESAP GUI and be redirected to</p> + <a + target="_blank" + rel="noopener noreferrer" + href="http://130.246.212.44/escape/" + > + Interactive analysis platform hosted by SKAO + </a> + </Alert> + ); } diff --git a/src/components/query/ASTRONVOResults.js b/src/components/query/ASTRONVOResults.js index 7bd41157f72f5448803752f9e445745b833a4314..1a5735b385b6690444b403f2acf21d0739a5773a 100644 --- a/src/components/query/ASTRONVOResults.js +++ b/src/components/query/ASTRONVOResults.js @@ -8,9 +8,9 @@ export default function ASTRONVOResults({ catalog }) { const { queryMap } = useContext(QueryContext); if (!queryMap) return null; if (queryMap.get(catalog).status === "fetched") { - if (queryMap.get(catalog).results.query_results.length === 0) + if (queryMap.get(catalog).results.results.length === 0) return <Alert variant="warning">No matching results found!</Alert>; - console.log(queryMap.get(catalog).results.query_results); + console.log(queryMap.get(catalog).results.results); return ( <> <Table className="mt-3" responsive> @@ -32,7 +32,7 @@ export default function ASTRONVOResults({ catalog }) { </tr> </thead> <tbody> - {queryMap.get(catalog).results.query_results.map((result) => { + {queryMap.get(catalog).results.results.map((result) => { return ( <tr key={result.result}> {/* <th> diff --git a/src/components/query/ApertifResults.js b/src/components/query/ApertifResults.js index 358b874ea05ff21ff46b5787d572ecac4c37ce1d..b360f12e6653e6da0080e96407dcd16fbfc4f24f 100644 --- a/src/components/query/ApertifResults.js +++ b/src/components/query/ApertifResults.js @@ -8,12 +8,9 @@ export default function ApertifResults({ catalog }) { const { queryMap } = useContext(QueryContext); if (!queryMap) return null; if (queryMap.get(catalog).status === "fetched") { - if (queryMap.get(catalog).results.query_results.length === 0) + if (queryMap.get(catalog).results.results.length === 0) return <Alert variant="warning">No matching results found!</Alert>; - console.log( - "Query results:", - queryMap.get(catalog).results.query_results["query_results"] - ); + console.log("Query results:", queryMap.get(catalog).results.results); return ( <> <Table className="mt-3" responsive> @@ -35,7 +32,7 @@ export default function ApertifResults({ catalog }) { </tr> </thead> <tbody> - {queryMap.get(catalog).results.query_results.map((result) => { + {queryMap.get(catalog).results.results.map((result) => { return ( <tr key={result.PID}> {/* <th> diff --git a/src/components/query/QueryIVOARegistry.js b/src/components/query/QueryIVOARegistry.js index c373f93c039dd2b6eeb538483efd98d140df9848..cf1101a5d9266a9e42c8ac3a5eb7ca5e00351250 100644 --- a/src/components/query/QueryIVOARegistry.js +++ b/src/components/query/QueryIVOARegistry.js @@ -1,12 +1,15 @@ import React, { useContext, useEffect } from "react"; import { useParams } from "react-router-dom"; import axios from "axios"; -import { Container, Button } from "react-bootstrap"; +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 "./QueryResults"; import parseQueryForm from "../../utils/form/parseQueryForm"; +import { IVOAContext } from "../../contexts/IVOAContext"; +import parseVOServiceForm from "../../utils/form/parseVOServiceForm"; +import VOServiceResults from "./VOServiceResults"; export default function QueryIVOARegistry() { // queryMap is a map of dictionaries, where each dictionary consists of @@ -16,6 +19,7 @@ export default function QueryIVOARegistry() { // "results": null} const { queryMap, formData, setFormData } = useContext(QueryContext); const { config, api_host, setConfigName } = useContext(GlobalContext); + const { selectedRegistry, queryStep, setQueryStep } = useContext(IVOAContext); const { uri } = useParams(); console.log("uri:", uri); @@ -47,11 +51,21 @@ export default function QueryIVOARegistry() { }, [uri]); useEffect(() => { - console.log(config.query_schema); + console.log("query schema:", config.query_schema); if (!formData) return; console.log("formData:", formData); - let gui = config.query_schema.name; - const queries = parseQueryForm(gui, formData); + const gui = config.query_schema.name; + let queries = []; + + if (queryStep === "run-query") { + selectedRegistry.forEach((access_url) => { + queries = [...queries, ...parseVOServiceForm(formData, access_url)]; + }); + } else { + queries = parseQueryForm(gui, formData); + } + + console.log("queries:", queries); // Ideally query for each catalog is sent to ESAP API Gateway, and query results is returned // This is under development in the backend at the moment @@ -59,6 +73,7 @@ export default function QueryIVOARegistry() { queries.forEach((query) => { queryMap.set(query.catalog, { catalog: query.catalog, + service_type: query.service_type, esapquery: query.esapquery, status: "fetching", results: null, @@ -69,6 +84,7 @@ export default function QueryIVOARegistry() { .then((queryResponse) => { queryMap.set(query.catalog, { catalog: query.catalog, + service_type: query.service_type, esapquery: query.esapquery, status: "fetched", results: queryResponse.data, @@ -77,6 +93,7 @@ export default function QueryIVOARegistry() { .catch(() => { queryMap.set(query.catalog, { catalog: query.catalog, + service_type: query.service_type, esapquery: query.esapquery, status: "error", results: null, @@ -108,38 +125,99 @@ export default function QueryIVOARegistry() { const uiSchemaProp = config.ui_schema ? { uiSchema: config.ui_schema } : {}; console.log("UI Schema props:", uiSchemaProp); + console.log("Form Data:", formData); - return ( - <Container fluid> - <Form - schema={config.query_schema} - ObjectFieldTemplate={formTemplate} - formData={formData} - onSubmit={({ formData }) => setFormData(formData)} - {...uiSchemaProp} - > - <div> - <Button type="submit">Get Registry Services</Button> - </div> - </Form> - {Array.from(queryMap.keys()).map((catalog) => { - console.log("catalog:", catalog); - const details = queryMap.get(catalog); - console.log("Details:", details); - console.log("Results:", details.results); - 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"> - <h4>List of registries</h4> - <QueryResults catalog={catalog} /> + if (queryStep === "run-query") { + uiSchemaProp.uiSchema = { + query: { "ui:widget": "textarea" }, + keyword: { "ui:widget": "hidden" }, + tap_schema: { "ui:widget": "hidden" }, + }; + console.log("new ui schema:", uiSchemaProp); + return ( + <Container fluid> + <Form + schema={config.query_schema} + ObjectFieldTemplate={formTemplate} + formData={formData} + onSubmit={({ formData }) => setFormData(formData)} + {...uiSchemaProp} + > + <RBForm.Control as="select" multiple> + {selectedRegistry.map((registry) => { + return <option>{registry}</option>; + })} + </RBForm.Control> + <div> + <Button className="mt-3" type="submit"> + Query Registry + </Button> </div> - ); - })} - </Container> - ); + </Form> + {selectedRegistry.map((registry) => { + const details = queryMap.get(registry); + console.log("Details:", details); + return ( + <div className="mt-3"> + <VOServiceResults catalog={registry} /> + </div> + ); + })} + </Container> + ); + } else { + return ( + <Container fluid> + <Form + schema={config.query_schema} + ObjectFieldTemplate={formTemplate} + formData={formData} + onSubmit={({ formData }) => setFormData(formData)} + {...uiSchemaProp} + > + <div> + <Button type="submit">Get Registry Services</Button> + </div> + </Form> + {Array.from(queryMap.keys()).map((catalog) => { + console.log("catalog:", catalog); + const details = queryMap.get(catalog); + console.log("Details:", details); + console.log("Results:", details.results); + 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 registries</h4> + </Col> + <Col> + {selectedRegistry.length === 0 ? ( + <></> + ) : ( + <Button + type="submit" + onClick={() => { + setQueryStep("run-query"); + }} + > + Query selected registry + </Button> + )} + </Col> + </Row> + <div className="mt-3"> + <QueryResults catalog={catalog} /> + </div> + </div> + ); + })} + </Container> + ); + } } diff --git a/src/components/query/VORegistryResults.js b/src/components/query/VORegistryResults.js index 828a9ae7670a24aa25c01f894bb8cc982cc28e84..d8481c93430700d4c8ef622cc70a238703f9fa6c 100644 --- a/src/components/query/VORegistryResults.js +++ b/src/components/query/VORegistryResults.js @@ -7,12 +7,18 @@ import { IVOAContext } from "../../contexts/IVOAContext"; export default function VORegistryResults({ catalog }) { const { queryMap } = useContext(QueryContext); - const { registryList, add, remove } = useContext(IVOAContext); + const { + selectedRegistry, + addRegistry, + removeRegistry, + registryList, + setRegistryList, + } = useContext(IVOAContext); // const [checkAll, setCheckAll] = useState(""); useEffect(() => { - console.log("RegistryList:", registryList); - }, [registryList]); + console.log("Selected Registry:", selectedRegistry); + }, [selectedRegistry]); // useEffect(() => { // console.log("checkAll:", checkAll); @@ -24,7 +30,10 @@ export default function VORegistryResults({ catalog }) { if (queryMap.get(catalog).status === "fetched") { if (queryMap.get(catalog).results.results.length === 0) return <Alert variant="warning">No matching results found!</Alert>; + console.log("VO Registry results:", queryMap.get(catalog).results.results); + setRegistryList(queryMap.get(catalog).results.results); + console.log("Registry List:", registryList); return ( <> @@ -40,12 +49,12 @@ export default function VORegistryResults({ catalog }) { // ? queryMap // .get(catalog) // .results.results.map((result) => { - // add(result.access_url); + // addRegistry(result.access_url); // }) // : queryMap // .get(catalog) // .results.results.map((result) => { - // remove(result.access_url); + // removeRegistry(result.access_url); // }); // }} /> @@ -70,8 +79,8 @@ export default function VORegistryResults({ catalog }) { onChange={(event) => { console.log(event.target.checked); event.target.checked - ? add(result.access_url) - : remove(result.access_url); + ? addRegistry(result.access_url) + : removeRegistry(result.access_url); }} /> </InputGroup> @@ -87,7 +96,7 @@ export default function VORegistryResults({ catalog }) { })} </tbody> </Table> - <Paginate /> + {/* <Paginate /> */} </> ); } else { diff --git a/src/components/query/VOServiceResults.js b/src/components/query/VOServiceResults.js new file mode 100644 index 0000000000000000000000000000000000000000..0f9ee8c79bc649c1c5e2b91202a8dcea1c09145d --- /dev/null +++ b/src/components/query/VOServiceResults.js @@ -0,0 +1,40 @@ +import React, { useContext } from "react"; +import { Alert, Table } from "react-bootstrap"; +import { QueryContext } from "../../contexts/QueryContext"; + +export default function VORegistryResults({ catalog }) { + const { queryMap } = useContext(QueryContext); + + if (!queryMap.get(catalog)) return null; + console.log("VO service queryMap:", queryMap.get(catalog)); + if (queryMap.get(catalog).status === "fetched") { + if (queryMap.get(catalog).results.results.length === 0) + return <Alert variant="warning">No matching results found!</Alert>; + return ( + <div> + <h1>Results from {catalog}</h1> + <Table className="mt-3" responsive> + <thead> + <tr className="bg-light"> + <th>Link to data</th> + </tr> + </thead> + <tbody> + {queryMap.get(catalog).results.results.map((result) => { + return ( + <tr key={result.result}> + <td> + <a href={result.result} rel="noopener noreferrer" download> + {result.result} + </a> + </td> + </tr> + ); + })} + </tbody> + </Table> + </div> + ); + } + return null; +} diff --git a/src/components/query/ZooniverseResults.js b/src/components/query/ZooniverseResults.js index f8814e4c5c3ab1cbc3c802750534604d9aa26591..69ff383d90af05b207d7549bfd45f6db2558ed42 100644 --- a/src/components/query/ZooniverseResults.js +++ b/src/components/query/ZooniverseResults.js @@ -1,25 +1,25 @@ -import React, { useContext, useState} from "react"; +import React, { useContext, useState } from "react"; import { Table, Alert } from "react-bootstrap"; import { QueryContext } from "../../contexts/QueryContext"; import LoadingSpinner from "../LoadingSpinner"; import Paginate, { pagination_fields } from "../Paginate"; const DATETIME_OPTIONS = { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", hour12: false, - timeZoneName: 'short' + timeZoneName: "short", }; -Object.isObject = function(obj) { - return (obj && obj.constructor === this) || false; +Object.isObject = function (obj) { + return (obj && obj.constructor === this) || false; }; -function renderArray(array, currentReactKey=""){ +function renderArray(array, currentReactKey = "") { return array.map((element, index) => { const updatedReactKey = `${currentReactKey}_${index}`; const separator = index < array.length - 1 ? ", " : ""; @@ -27,97 +27,132 @@ function renderArray(array, currentReactKey=""){ }); } -function renderObject(object, currentReactKey=""){ +function renderObject(object, currentReactKey = "") { return ( <Table key={currentReactKey + "_objTable"}> - <tbody> - {Object.entries(object).map(([key, value]) =>{ - const updatedReactKey=`${currentReactKey}_${key}`; - return( - <tr key={updatedReactKey}><td className="b">{key}</td><td>{renderIfCompound(value, updatedReactKey)}</td></tr> - ) - })} - </tbody> + <tbody> + {Object.entries(object).map(([key, value]) => { + const updatedReactKey = `${currentReactKey}_${key}`; + return ( + <tr key={updatedReactKey}> + <td className="b">{key}</td> + <td>{renderIfCompound(value, updatedReactKey)}</td> + </tr> + ); + })} + </tbody> </Table> - ) + ); } -function renderIfCompound(element, currentReactKey="", separatorForPod="", floatPrecision=3) { +function renderIfCompound( + element, + currentReactKey = "", + separatorForPod = "", + floatPrecision = 3 +) { if (Array.isArray(element)) { return renderArray(element, currentReactKey, separatorForPod); } else if (Object.isObject(element)) { return renderObject(element, currentReactKey, separatorForPod); } else if (typeof element === "boolean") { - return JSON.stringify(element) + separatorForPod - } else if (Number.isInteger(element)){ + return JSON.stringify(element) + separatorForPod; + } else if (Number.isInteger(element)) { return element.toString() + separatorForPod; } else { - try{ + try { return element.toFixed(floatPrecision) + separatorForPod; - } - catch(err){ - return `${element}` + separatorForPod + } catch (err) { + return `${element}` + separatorForPod; } } } function titleCase(string) { - var sentence = string.toLowerCase().split(" "); - for(var i = 0; i< sentence.length; i++){ - sentence[i] = sentence[i][0].toUpperCase() + sentence[i].slice(1); - } - return sentence.join(" "); - } + var sentence = string.toLowerCase().split(" "); + for (var i = 0; i < sentence.length; i++) { + sentence[i] = sentence[i][0].toUpperCase() + sentence[i].slice(1); + } + return sentence.join(" "); +} -function newPageCallback(setPage){ +function newPageCallback(setPage) { return (args) => { - if(args.target){ - setPage(parseFloat(args.target.text)); - } + if (args.target) { + setPage(parseFloat(args.target.text)); + } }; } -function ZooniverseProjectResults(context){ - const { queryMap, page, setPage } = context; - const date_formatter=new Intl.DateTimeFormat("default", DATETIME_OPTIONS); +function ZooniverseProjectResults(context) { + const { queryMap, page, setPage } = context; + const date_formatter = new Intl.DateTimeFormat("default", DATETIME_OPTIONS); const result = queryMap.get("zooniverse_projects").results.query_results[0]; const numPages = result.pages; - const mandatory_fields = ["launch_date", "created_at", "live", "updated_at", "project_id", "display_name", "slug"]; - const remaining_fields = Object.keys(result).filter(key => !(mandatory_fields.includes(key) || pagination_fields.includes(key))); + const mandatory_fields = [ + "launch_date", + "created_at", + "live", + "updated_at", + "project_id", + "display_name", + "slug", + ]; + const remaining_fields = Object.keys(result).filter( + (key) => + !(mandatory_fields.includes(key) || pagination_fields.includes(key)) + ); const remaining_headers = remaining_fields.map((field) => { - const title=titleCase(field.replace("_", " ")); - return (<th key={`project_header_${field}`}>{title}</th>); + const title = titleCase(field.replace("_", " ")); + return <th key={`project_header_${field}`}>{title}</th>; }); - return ( - <> - <Paginate getNewPage={newPageCallback(setPage)} currentPage={page} numAdjacent={3} numPages={numPages}/> - <Table className="mt-3" responsive> - <thead> - <tr className="bg-light"> - {/* <th> + return ( + <> + <Paginate + getNewPage={newPageCallback(setPage)} + currentPage={page} + numAdjacent={3} + numPages={numPages} + /> + <Table className="mt-3" responsive> + <thead> + <tr className="bg-light"> + {/* <th> <InputGroup> <InputGroup.Checkbox /> </InputGroup> </th> */} - <th>ID</th> - <th>Display Name</th> - <th>Created</th> - <th>Updated</th> - <th>Launched</th> - <th>Live</th> - <th>View</th> - {remaining_headers} - </tr> - </thead> - <tbody> - {queryMap.get("zooniverse_projects").results.query_results.map((result) => { - const launch_date = result.launch_date ? date_formatter.format(new Date(result.launch_date)) : "Not Launched"; - const created_at = date_formatter.format(new Date(result.created_at)); - const updated_at = date_formatter.format(new Date(result.updated_at)); - const live = result.live ? "Yes" : "No" + <th>ID</th> + <th>Display Name</th> + <th>Created</th> + <th>Updated</th> + <th>Launched</th> + <th>Live</th> + <th>View</th> + {remaining_headers} + </tr> + </thead> + <tbody> + {queryMap + .get("zooniverse_projects") + .results.query_results.map((result) => { + const launch_date = result.launch_date + ? date_formatter.format(new Date(result.launch_date)) + : "Not Launched"; + const created_at = date_formatter.format( + new Date(result.created_at) + ); + const updated_at = date_formatter.format( + new Date(result.updated_at) + ); + const live = result.live ? "Yes" : "No"; const remaining_cells = remaining_fields.map((field) => { const reactKey = `project_${result.project_id}_${field}`; - return (<td key={reactKey}>{renderIfCompound(result[field], reactKey)}</td>); + return ( + <td key={reactKey}> + {renderIfCompound(result[field], reactKey)} + </td> + ); }); return ( <tr key={`project_${result.project_id}`}> @@ -132,84 +167,122 @@ function ZooniverseProjectResults(context){ <td>{updated_at}</td> <td>{launch_date}</td> <td>{live}</td> - <td><a href={`https://zooniverse.org/projects/${result.slug}`}>Link</a></td> + <td> + <a href={`https://zooniverse.org/projects/${result.slug}`}> + Link + </a> + </td> {remaining_cells} </tr> ); })} - </tbody> - </Table> - <Paginate getNewPage={newPageCallback(setPage)} currentPage={page} numAdjacent={3} numPages={numPages}/> - </> - ); - + </tbody> + </Table> + <Paginate + getNewPage={newPageCallback(setPage)} + currentPage={page} + numAdjacent={3} + numPages={numPages} + /> + </> + ); } -function ZooniverseWorkflowResults(context){ - const { queryMap, page, setPage } = context; - let date_formatter=new Intl.DateTimeFormat("default", DATETIME_OPTIONS); +function ZooniverseWorkflowResults(context) { + const { queryMap, page, setPage } = context; + let date_formatter = new Intl.DateTimeFormat("default", DATETIME_OPTIONS); let result = queryMap.get("zooniverse_workflows").results.query_results[0]; let result_workflow = result.workflows[0]; const numPages = result.pages; - let mandatory_fields = ["created_at", "updated_at", "workflow_id", "display_name"]; - let remaining_fields = Object.keys(result_workflow).filter(key => !(mandatory_fields.includes(key) || pagination_fields.includes(key))); + let mandatory_fields = [ + "created_at", + "updated_at", + "workflow_id", + "display_name", + ]; + let remaining_fields = Object.keys(result_workflow).filter( + (key) => + !(mandatory_fields.includes(key) || pagination_fields.includes(key)) + ); let remaining_headers = remaining_fields.map((field) => { - let title=titleCase(field.replace("_", " ")); - return (<th key={`project_header_${field}`}>{title}</th>); + let title = titleCase(field.replace("_", " ")); + return <th key={`project_header_${field}`}>{title}</th>; }); - return ( - <> - <Paginate getNewPage={newPageCallback(setPage)} currentPage={page} numAdjacent={3} numPages={numPages}/> - {queryMap.get("zooniverse_workflows").results.query_results.map((project) => { - return (<div key={project.project_id}> - <h4>{project.display_name}</h4> - <Table className="mt-3" responsive> - <thead> - <tr className="bg-light"> - {/* <th> + return ( + <> + <Paginate + getNewPage={newPageCallback(setPage)} + currentPage={page} + numAdjacent={3} + numPages={numPages} + /> + {queryMap + .get("zooniverse_workflows") + .results.query_results.map((project) => { + return ( + <div key={project.project_id}> + <h4>{project.display_name}</h4> + <Table className="mt-3" responsive> + <thead> + <tr className="bg-light"> + {/* <th> <InputGroup> <InputGroup.Checkbox /> </InputGroup> </th> */} - <th>ID</th> - <th>Display Name</th> - <th>Created</th> - <th>Updated</th> - {remaining_headers} - {/* <th>View</th> */} - </tr> - </thead> - <tbody> - {project.workflows.map((workflow) => { - let created_at = date_formatter.format(new Date(workflow.created_at)); - let updated_at = date_formatter.format(new Date(workflow.updated_at)); - let remaining_cells = remaining_fields.map((field) => { - let reactKey = `workflow_${workflow.workflow_id}_${field}`; - return (<td key={reactKey}>{renderIfCompound(workflow[field], reactKey)}</td>); - }); - return ( - <tr key={`workflow_${workflow.workflow_id}`}> - {/* <th> + <th>ID</th> + <th>Display Name</th> + <th>Created</th> + <th>Updated</th> + {remaining_headers} + {/* <th>View</th> */} + </tr> + </thead> + <tbody> + {project.workflows.map((workflow) => { + let created_at = date_formatter.format( + new Date(workflow.created_at) + ); + let updated_at = date_formatter.format( + new Date(workflow.updated_at) + ); + let remaining_cells = remaining_fields.map((field) => { + let reactKey = `workflow_${workflow.workflow_id}_${field}`; + return ( + <td key={reactKey}> + {renderIfCompound(workflow[field], reactKey)} + </td> + ); + }); + return ( + <tr key={`workflow_${workflow.workflow_id}`}> + {/* <th> <InputGroup> <InputGroup.Checkbox /> </InputGroup> </th> */} - <td>{workflow.workflow_id}</td> - <td>{workflow.display_name}</td> - <td>{created_at}</td> - <td>{updated_at}</td> - {remaining_cells} - {/* <td><a href={`https://zooniverse.org/workflows/${workflow.slug}`}>Link</a></td> */} - </tr> - ); - })} - </tbody> - </Table> - </div>); + <td>{workflow.workflow_id}</td> + <td>{workflow.display_name}</td> + <td>{created_at}</td> + <td>{updated_at}</td> + {remaining_cells} + {/* <td><a href={`https://zooniverse.org/workflows/${workflow.slug}`}>Link</a></td> */} + </tr> + ); + })} + </tbody> + </Table> + </div> + ); })} - <Paginate getNewPage={newPageCallback(setPage)} currentPage={page} numAdjacent={3} numPages={numPages}/> - </> - ); + <Paginate + getNewPage={newPageCallback(setPage)} + currentPage={page} + numAdjacent={3} + numPages={numPages} + /> + </> + ); } export default function ZooniverseResults({ catalog }) { @@ -218,13 +291,11 @@ export default function ZooniverseResults({ catalog }) { if (context.queryMap.get(catalog).status === "fetched") { if (context.queryMap.get(catalog).results.query_results.length === 0) return <Alert variant="warning">No matching results found!</Alert>; - else if (catalog === "zooniverse_projects"){ + else if (catalog === "zooniverse_projects") { return ZooniverseProjectResults(context); - } - else if (catalog === "zooniverse_workflows"){ + } else if (catalog === "zooniverse_workflows") { return ZooniverseWorkflowResults(context); - } - else { + } else { return <Alert variant="warning">Unrecognised Zooniverse Catalog!</Alert>; } } else { diff --git a/src/contexts/GlobalContext.js b/src/contexts/GlobalContext.js index e18b2eb607345a265f8060ccbf209a52e6d63753..d8c42dcfbba472643df6364b482f3c14dfd3a148 100644 --- a/src/contexts/GlobalContext.js +++ b/src/contexts/GlobalContext.js @@ -5,10 +5,10 @@ import getCookie from "../utils/getCookie"; export const GlobalContext = createContext(); export function GlobalContextProvider({ children }) { - console.log("ASTRON ESAP version 14 aug 2020"); + console.log("ASTRON ESAP version ", Date()); const api_host = process.env.NODE_ENV === "development" - ? "http://localhost:15671/esap-api/" + ? "http://sdc.astron.nl:5555/esap-api/" : "/esap-api/"; const [config, setConfig] = useState(); diff --git a/src/contexts/IVOAContext.js b/src/contexts/IVOAContext.js index eba8707e13090945b095b033a21600474fd60d29..a5363958e05f9505b8046e3577721360e5c4b50d 100644 --- a/src/contexts/IVOAContext.js +++ b/src/contexts/IVOAContext.js @@ -1,25 +1,49 @@ import React, { createContext, useState } from "react"; +import useMap from "../hooks/useMap"; export const IVOAContext = createContext(); export function IVOAContextProvider({ children }) { const [registryList, setRegistryList] = useState([]); + const [selectedRegistry, setSelectedRegistry] = useState([]); + const [queryStep, setQueryStep] = useState("get-services"); + /* + IVOA query steps: + 1. get-services + 2. run-query: query selected registry + */ + + // For testing purpose + // start manual setup block + //const [queryStep, setQueryStep] = useState("run-query"); + // const [selectedRegistry, setSelectedRegistry] = useState([ + // // "http://astron.nl/tap", + // // "http://aip.gavo.org/tap", + // // "http://archive.stsci.edu/caomtap", + // "http://vao.stsci.edu/CAOMTAP/TapService.aspx", + // ]); + // end block + function handleAddRegistry(access_url) { - setRegistryList([...registryList, access_url]); + setSelectedRegistry([...selectedRegistry, access_url]); } function handleRemoveRegistry(access_url) { - const copy = [...registryList]; + const copy = [...selectedRegistry]; const index = copy.findIndex((url) => url === access_url); copy.splice(index, 1); - setRegistryList(copy); + setSelectedRegistry(copy); } return ( <IVOAContext.Provider value={{ + selectedRegistry, + addRegistry: handleAddRegistry, + removeRegistry: handleRemoveRegistry, registryList, - add: handleAddRegistry, - remove: handleRemoveRegistry, + setRegistryList, + queryStep, + setQueryStep, }} > {children} diff --git a/src/routes/Routes.js b/src/routes/Routes.js index 5cea8e2796c348ba82c3f4e7cccb50a87a2ced3d..cc4098e741edcc92f1ea27b75432113034c25f56 100644 --- a/src/routes/Routes.js +++ b/src/routes/Routes.js @@ -42,6 +42,13 @@ export default function Routes() { <Route exact path="/login" component={handleLogin} /> <Route exact path="/logout" component={handleLogout} /> <Route exact path="/archives/:uri" component={ArchiveDetails} /> + <Route exact path="/archives/ivoa/query"> + <QueryContextProvider> + <IVOAContextProvider> + <QueryIVOARegistry /> + </IVOAContextProvider> + </QueryContextProvider> + </Route> <Route exact path="/archives/:uri/query"> <QueryContextProvider> <QueryCatalogs /> diff --git a/src/utils/form/parseADEXForm.js b/src/utils/form/parseADEXForm.js index d2f9460dc23fc6ea74995f1f051a881a8590194f..351fabef237b4d6f60208855092efa1e64e4060b 100644 --- a/src/utils/form/parseADEXForm.js +++ b/src/utils/form/parseADEXForm.js @@ -6,7 +6,7 @@ export default function ParseADEXForm(formData) { // "esapquery": "querystring"} let query = ""; let formInput = Object.entries(formData); - console.log(formInput); + console.log("formInput:", formInput); for (let [key, value] of formInput) { console.log(`${key}: ${value}`); diff --git a/src/utils/form/parseASTRONVOForm.js b/src/utils/form/parseASTRONVOForm.js index 8724fc5aabc2c2c9d2a6cda65687d5f6d5b78b1d..9162c828a9635cabe750e5dbbcccfd933dc8ea4c 100644 --- a/src/utils/form/parseASTRONVOForm.js +++ b/src/utils/form/parseASTRONVOForm.js @@ -5,7 +5,7 @@ export default function ParseASTRONVOForm(formData) { // "esapquery": "querystring"} let query = ""; let formInput = Object.entries(formData); - console.log(formInput); + console.log("formInput:", formInput); for (let [key, value] of formInput) { console.log(`${key}: ${value}`); diff --git a/src/utils/form/parseIVOAForm.js b/src/utils/form/parseIVOAForm.js index 640227870591c5f3dbbcb864355cc7240c5fb2df..e518ff0ccaf91f1b5730b7f98bdc8fe9df92bef7 100644 --- a/src/utils/form/parseIVOAForm.js +++ b/src/utils/form/parseIVOAForm.js @@ -22,12 +22,14 @@ export default function ParseIVOAForm(formData) { // "status": "null|fetching|fetched", // "results": null} let catalog = formInput.find(([key]) => key === "catalog")[1]; + let service_type = formInput.find(([key]) => key === "service_type")[1]; let esapquery = "get-services/?" + query + `${`${query}` ? "&" : ""}dataset_uri=` + catalog; queries.push({ catalog: catalog, + service_type: service_type, esapquery: esapquery, }); diff --git a/src/utils/form/parseVOServiceForm.js b/src/utils/form/parseVOServiceForm.js new file mode 100644 index 0000000000000000000000000000000000000000..c42aec9a71378c01d5b44ba9d9e675ff0b09abf9 --- /dev/null +++ b/src/utils/form/parseVOServiceForm.js @@ -0,0 +1,42 @@ +export default function ParseVOServiceForm(formData, access_url) { + let queries = []; + // queries is an array of dictionaries, where each dictionary consists of + // {"catalog": "catalogname", + // "esapquery": "querystring"} + let query = ""; + let formInput = Object.entries(formData); + console.log(formInput); + + // IVOA query consists of multiple steps + // Step 1: get list of registry services + + for (let [key, value] of formInput) { + console.log(`${key}: ${value}`); + // Ignore value of keyword from get-services query, in this step keyword will not be used. + if (value && value !== "all" && key !== "catalog" && key !== "keyword") { + query += `${`${query}` ? "&" : ""}` + key + "=" + value; + } + } + query += `${`${query}` ? "&" : ""}` + "access_url=" + access_url; + + console.log("Query:", query); + // If catalog is set to "all", query for each catalog needs to be generated + // {"catalog": "catalogname", + // "catalogquery": "querystring", + // "status": "null|fetching|fetched", + // "results": null} + let catalog = formInput.find(([key]) => key === "catalog")[1]; + let service_type = formInput.find(([key]) => key === "service_type")[1]; + + let esapquery = + "query/?" + query + `${`${query}` ? "&" : ""}dataset_uri=` + catalog; + + queries.push({ + catalog: access_url, + service_type: service_type, + esapquery: esapquery, + }); + + console.log("Queries:", queries); + return queries; +}