Newer
Older
import React, { useContext, useEffect } from "react";
import { Alert, Form, Table } from "react-bootstrap";
import { BasketContext } from "../../../contexts/BasketContext";

Nico Vermaas
committed
import { GlobalContext } from "../../../contexts/GlobalContext";
import { QueryContext } from "../../../contexts/QueryContext";
import AddToBasket from "../../basket/AddToBasketCheckBox";

Nico Vermaas
committed
import LoadingSpinner from "../../LoadingSpinner";
import Paginate, { pagination_fields } from "../../Paginate";
const DATETIME_OPTIONS = {

Zheng Meyer
committed
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",

Zheng Meyer
committed
timeZoneName: "short",

Zheng Meyer
committed
return (obj && obj.constructor === this) || false;
Hugh Dickinson
committed
};

Zheng Meyer
committed
function renderArray(array, currentReactKey = "") {
Hugh Dickinson
committed
return array.map((element, index) => {
const updatedReactKey = `${currentReactKey}_${index}`;
const separator = index < array.length - 1 ? ", " : "";
return renderIfCompound(element, updatedReactKey, separator);
Hugh Dickinson
committed
});
}

Zheng Meyer
committed
function renderObject(object, currentReactKey = "") {
Hugh Dickinson
committed
return (
<Table key={currentReactKey + "_objTable"}>

Zheng Meyer
committed
<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>
Hugh Dickinson
committed
</Table>

Zheng Meyer
committed
);
Hugh Dickinson
committed
}

Zheng Meyer
committed
function renderIfCompound(
element,
currentReactKey = "",
separatorForPod = "",
floatPrecision = 3
) {
Hugh Dickinson
committed
if (Array.isArray(element)) {
return renderArray(element, currentReactKey, separatorForPod);
Hugh Dickinson
committed
} else if (Object.isObject(element)) {
return renderObject(element, currentReactKey, separatorForPod);
Hugh Dickinson
committed
} else if (typeof element === "boolean") {

Zheng Meyer
committed
return JSON.stringify(element) + separatorForPod;
return element.toString() + separatorForPod;
} else {
return element.toFixed(floatPrecision) + separatorForPod;
} catch (err) {
return `${element}` + separatorForPod;
Hugh Dickinson
committed
}
}
function titleCase(string) {

Zheng Meyer
committed
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(" ");
}
Hugh Dickinson
committed
return (args) => {
if (args.target) {
setPage(parseFloat(args.target.text));
}
};
function projectBasketItem(projectId, category) {
Hugh Dickinson
committed
return {
archive: "zooniverse",
Hugh Dickinson
committed
catalog: "project",
project_id: projectId,
category: category
};
}
function workflowBasketItem(projectId, workflowId, category) {
Hugh Dickinson
committed
return {
archive: "zooniverse",
Hugh Dickinson
committed
catalog: "workflow",
project_id: projectId,
workflow_id: workflowId,
category: category
};
}
Hugh Dickinson
committed
function ZooniverseProjectResults(context) {
const { queryMap, page, setPage } = context;
const date_formatter = new Intl.DateTimeFormat("default", DATETIME_OPTIONS);
const result = queryMap.get("zooniverse_projects").results.results[0];
const numPages = result.pages;

Zheng Meyer
committed
"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))

Zheng Meyer
committed
);
const remaining_headers = remaining_fields.map((field) => {

Zheng Meyer
committed
return <th key={`project_header_${field}`}>{title}</th>;
Hugh Dickinson
committed
});

Zheng Meyer
committed
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>Select Classification Data</th>
<th>Select Subject Data</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.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)

Zheng Meyer
committed
);
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 (
<tr key={`project_${result.project_id}`}>
{/* <th>
<InputGroup>
<InputGroup.Checkbox />
</InputGroup>
</th> */}
<AddToBasket id={`selectClassifications_${result.project_id}`} item={projectBasketItem(result.project_id, "classifications")} />
<AddToBasket id={`selectSubjects_${result.project_id}`} item={projectBasketItem(result.project_id, "subjects")} />
</td>
<td>{result.project_id}</td>
<td>{result.display_name}</td>
<td>{created_at}</td>
<td>{updated_at}</td>
<td>{launch_date}</td>
<td>{live}</td>
<td>
<a href={`https://zooniverse.org/projects/${result.slug}`}>
Link
</td>
{remaining_cells}
</tr>
);
})}
</tbody>
</Table>
</Form>
<Paginate
getNewPage={newPageCallback(setPage)}
currentPage={page}
numAdjacent={3}
numPages={numPages}
/>

Zheng Meyer
committed
</>
);
Hugh Dickinson
committed
function ZooniverseWorkflowResults(context) {

Zheng Meyer
committed
let date_formatter = new Intl.DateTimeFormat("default", DATETIME_OPTIONS);
let result = queryMap.get("zooniverse_workflows").results.results[0];

Zheng Meyer
committed
let result_workflow = result.workflows[0];
const numPages = result.pages;

Zheng Meyer
committed
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))

Zheng Meyer
committed
);
Hugh Dickinson
committed
let remaining_headers = remaining_fields.map((field) => {

Zheng Meyer
committed
let title = titleCase(field.replace("_", " "));
return <th key={`project_header_${field}`}>{title}</th>;
Hugh Dickinson
committed
});

Zheng Meyer
committed
return (
<>
<Paginate
getNewPage={newPageCallback(setPage)}
currentPage={page}
numAdjacent={3}
numPages={numPages}
/>
Hugh Dickinson
committed
<Form>

Nico Vermaas
committed
{queryMap
.get("zooniverse_workflows")
.results.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>Select Classification Data</th>
<th>Select Subject Data</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)

Zheng Meyer
committed
);
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>
<AddToBasket id={`selectClassifications_${workflow.workflow_id}`} item={workflowBasketItem(result.project_id, workflow.workflow_id, "classifications")} />
</td>
<td>
<AddToBasket id={`selectSubjects_${workflow.workflow_id}`} item={workflowBasketItem(result.project_id, workflow.workflow_id, "subjects")} />
</td>
<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>
);
})}
Hugh Dickinson
committed
</Form>
<Paginate
getNewPage={newPageCallback(setPage)}
currentPage={page}
numAdjacent={3}
numPages={numPages}
/>

Zheng Meyer
committed
</>
);
}
export default function ZooniverseResults({ catalog }) {
const context = useContext(QueryContext);
const basketContext = useContext(BasketContext);
const { queryMap, page } = useContext(QueryContext);
const { api_host } = useContext(GlobalContext);
const usp = new URLSearchParams(queryMap.get(catalog).esapquery);
usp.set("page", page);
queryMap.set(catalog, {
catalog: catalog,
page: page,
esapquery: usp.toString(),
});
const url = api_host + "query/query/?" + queryMap.get(catalog).esapquery;
axios
.get(url)
.then((queryResponse) => {
queryMap.set(catalog, {
catalog: catalog,
esapquery: queryMap.get(catalog).esapquery,
page: page,
status: "fetched",
results: queryResponse.data,
});
})
.catch(() => {
queryMap.set(catalog, {
catalog: catalog,
esapquery: queryMap.get(catalog).esapquery,
page: page,
status: "error",
results: null,
});
});
}, [page]); // eslint-disable-line react-hooks/exhaustive-deps
// FIXME: React Hook useEffect has missing dependencies: 'api_host', 'catalog', and 'queryMap'. Either include them or remove the dependency array react-hooks/exhaustive-deps
// FIXME: breaks the rules of hooks!
if (!context.queryMap) return null;
if (context.queryMap.get(catalog).status === "fetched") {
if (context.queryMap.get(catalog).results.results.length === 0)
return <Alert variant="warning">No matching results found!</Alert>;

Zheng Meyer
committed
else if (catalog === "zooniverse_projects") {
console.log(`basketContext -> ${basketContext}`);
console.log(basketContext);
return ZooniverseProjectResults(context, basketContext);

Zheng Meyer
committed
} else if (catalog === "zooniverse_workflows") {
return ZooniverseWorkflowResults(context, basketContext);

Zheng Meyer
committed
} else {
return <Alert variant="warning">Unrecognised Zooniverse Catalog!</Alert>;
}
} else {
return <LoadingSpinner />;
}
}