diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..e23a45a8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:21.04 +LABEL org.opencontainers.image.source https://github.com/biocompute-objects/portal +ENV DEBIAN_FRONTEND=noninteractive + +EXPOSE 3000 + +RUN apt-get update && apt-get install -y nodejs npm vim + +WORKDIR /portal + +COPY src ./src +COPY package.json . +COPY jsconfig.json . +COPY public public +COPY docs docs + +RUN npm install --quiet --legacy-peer-deps +#RUN npm audit fix --legacy-peer-deps + +CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/README.md b/README.md index e552b773..bdd54ded 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,20 @@ The git folder (application) that contains all of the user information for the p 1. python3 manage.py runserver 8000 +## Containerization + +The web portal can be containerized for easier development and deployment. + +### Building in a container with docker + +You can build the container by running the build command: + +`docker build -t bco_portal .` + +### Running the container with docker + +You can run the container via docker through the following command: + +`docker run --network host --rm -t bco_portal` + +This will set the portal to be available at `localhost:3000` on the host machine. \ No newline at end of file diff --git a/src/views/account/AccountView/ServerInfo.js b/src/views/account/AccountView/ServerInfo.js index a1eaddb3..fdae0326 100644 --- a/src/views/account/AccountView/ServerInfo.js +++ b/src/views/account/AccountView/ServerInfo.js @@ -212,7 +212,7 @@ const EnhancedTableToolbar = (props) => { // This will allow the background to update with // the updated server list. setServerAdded(true); - + // setSelected(false); } else { // Display whatever the server said. console.log('Failed to remove the API server because: ', result.data.detail); diff --git a/src/views/objects/ObjectsListView/Results.js b/src/views/objects/ObjectsListView/Results.js index d3840d9d..6e0fba31 100644 --- a/src/views/objects/ObjectsListView/Results.js +++ b/src/views/objects/ObjectsListView/Results.js @@ -370,5 +370,5 @@ export default function Results({ rowInfo }) { } Results.propTypes = { - rowInfo: PropTypes.object.isRequired, + rowInfo: PropTypes.array.isRequired, }; diff --git a/src/views/objects/ObjectsListView/index.js b/src/views/objects/ObjectsListView/index.js index b9ed19af..86d51cd6 100644 --- a/src/views/objects/ObjectsListView/index.js +++ b/src/views/objects/ObjectsListView/index.js @@ -57,10 +57,24 @@ const ObjectsListView = () => { // Row data const rowData = []; + const getObjs = function getObjects(item) { + return fetch(`${item.public_hostname}/api/objects/token/`, { + method: 'POST', + body: JSON.stringify({ + POST_api_objects_token: {} + }), + headers: { + Authorization: `Token ${item.token}`, + 'Content-type': 'application/json; charset=UTF-8' + } + }).then((response) => { + return [item.public_hostname, response.json()]; + }); + }; + const getObjectsListing = () => { // First get the API info. let ApiInfo = JSON.parse(localStorage.getItem('user')); - // If there is no user info stored, assume we're the anonymous user. if (ApiInfo === null) { // Use the anon token, which is publicly available. @@ -69,51 +83,47 @@ const ObjectsListView = () => { // There was a user. ApiInfo = ApiInfo.apiinfo; } - - console.log('ApiInfo', ApiInfo); - + // console.log(ApiInfo); // Get the info for each API. - ApiInfo.forEach((item) => { - // Call the API using the server information - // associated with the user. - fetch(`${item.public_hostname}/api/objects/token/`, { - method: 'POST', - body: JSON.stringify({ - POST_api_objects_token: {} - }), - headers: { - Authorization: `Token ${item.token}`, - 'Content-type': 'application/json; charset=UTF-8' + const results = Promise.all(ApiInfo.map(getObjs)); + results.then((data) => { + console.log('Output ', data); + // data.forEach((d) => { + const promises = data.map((apiAndPromise) => { + // The provenance domain name may not be defined. + if (apiAndPromise.length !== 2) { + console.log("ERROR: This shouldn't ever be hit."); } - }).then((response) => response.json()).then((data) => { - console.log('data: ',item.public_hostname, data); - - data.map((d_item) => { - // The provenance domain name may not be defined. - try { - d_item.name = d_item.contents.provenance_domain.name; - } catch (TypeError) { - d_item.name = 'N/A'; - } - - rowData.push( - createData( - d_item.name, - item.public_hostname, - d_item.contents, - d_item.last_update, - d_item.object_class, - d_item.object_id, - d_item.owner_group, - d_item.owner_user, - d_item.prefix, - d_item.schema, - d_item.state, - ) - ); + const apiServer = apiAndPromise[0]; + return apiAndPromise[1].then((dItems) => { + dItems.forEach((dItem) => { + try { + dItem.name = dItem.contents.provenance_domain.name; + } catch (TypeError) { + dItem.name = 'N/A'; + } + + rowData.push( + createData( + dItem.name, + apiServer, + dItem.contents, + dItem.last_update, + dItem.object_class, + dItem.object_id, + dItem.owner_group, + dItem.owner_user, + dItem.prefix, + dItem.schema, + dItem.state, + ) + ); + }); }); - - // We're no longer loading. + }); + // We should have all of the promises for the various servers now + // wait for them all to finish and then populate the table. + Promise.all(promises).then((r) => { setRows(rowData); setLoading(false); });