diff --git a/src/src/components/collections/collections.jsx b/src/src/components/collections/collections.jsx index 22a2d282..fb829b3b 100644 --- a/src/src/components/collections/collections.jsx +++ b/src/src/components/collections/collections.jsx @@ -4,6 +4,7 @@ import "../../App.css"; import SearchComponent from "../search/SearchComponent"; import {COLUMN_DEF_MIXED,COLUMN_DEF_MIXED_SM} from "../search/table_constants"; import { entity_api_get_entity,entity_api_create_entity, entity_api_update_entity} from '../../service/entity_api'; +import {ingest_api_publish_collection,ingest_api_user_admin} from '../../service/ingest_api'; import { getPublishStatusColor } from "../../utils/badgeClasses"; import { generateDisplaySubtypeSimple_UBKG } from "../../utils/display_subtypes"; import Papa from 'papaparse'; @@ -15,7 +16,7 @@ import Dialog from "@material-ui/core/Dialog"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import GroupModal from "../uuid/groupModal"; - +import LoadingButton from '@mui/lab/LoadingButton'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; @@ -23,7 +24,7 @@ import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import {DataGrid,GridToolbar} from "@mui/x-data-grid"; - +import {ErrBox} from "../../utils/ui_elements"; import Alert from '@mui/material/Alert'; import Collapse from '@mui/material/Collapse'; import LinearProgress from '@material-ui/core/LinearProgress'; @@ -48,20 +49,29 @@ export function CollectionForm (props){ var [associatedEntities, setassociatedEntities] = useState([]); var [associatedEntitiesInitial, setassociatedEntitiesInitial] = useState([]); var [selectedSources, setSelectedSources] = useState([]); + var [publishing, setPublishing] = useState(false); var [fileDetails, setFileDetails] = useState(); var [buttonState, setButtonState] = useState(''); var [warningOpen, setWarningOpen] = React.useState(false); - var [openGroupModal, setOpenGroupModal] = useState(false - - - ); + var [openGroupModal, setOpenGroupModal] = useState(false); var [lookupShow, setLookupShow] = useState(false); var [loadingDatasets, setLoadingDatasets] = useState(true); var [hideUUIDList, setHideUUIDList] = useState(true); var [loadUUIDList, setLoadUUIDList] = useState(false); var [validatingSubmitForm, setValidatingSubmitForm] = useState(false); var [entityInfo, setEntityInfo] = useState(); + var [userAdmin, setUserAdmin] = useState(false); var [pageError, setPageError] = useState(""); + // var [publishError, setPublishError] = useState({ + // status:"", + // message:"", + // }); + // @TODO: See what we can globalize/memoize/notize here + var [errorHandler, setErrorHandler] = useState({ + status: "", + message: "", + isError: null + }); var [formWarnings, setFormWarnings] = useState({ bulk_dataset_uuids:"" }); @@ -87,6 +97,18 @@ export function CollectionForm (props){ var [datatypeList] = useState(props.dtl_all); var [editingCollection] = useState(props.editingCollection); + + useEffect(() => { + ingest_api_user_admin(JSON.parse(localStorage.getItem("info")).groups_token) + .then((results) => { + console.debug('%c◉ ADMINCHECK ', 'color:#3F007b', results); + setUserAdmin(results) + }) + .catch((err) => { + console.debug('%c⭗', 'color:#1f005d', "ingest_api_user_admin ERR", err ); + }) + }, []); + useEffect(() => { if (editingCollection) { setassociatedEntities([]) @@ -456,6 +478,27 @@ export function CollectionForm (props){ }); } + const handlePublish = () => { + setPublishing(true) + ingest_api_publish_collection(props.authToken,editingCollection.uuid) + .then((response) => { + if(response.status === 200){ + console.debug('%c◉ Good ingest_api_publish_collection ', 'color:#00ff7b', response); + props.onProcessed(response.results); + }else{ + console.debug('%c◉ ingest_api_publish_collection Bad result', 'color:#ff337b', response); + setPublishing(false) + let authMessage = response.status === 401 ? "User must be Authorized" : response.results.error.toString(); + setPageError(response.status + " | " + authMessage); + } + }) + .catch((error) => { + console.debug('%c⭗ handlePublishErr Broken Result', 'color:#ff005d', error); + setPageError(error.status + " | " + error.message); + setPublishing(false); + }); + } + const handleUpdate = (formSubmit) => { // Need to only pass what's changed now console.debug('%c◉ formSubmit ', 'color:#00ff7b',formSubmit ); @@ -876,6 +919,18 @@ export function CollectionForm (props){ value={formValues.title} /> + {editingCollection && editingCollection.doi_url && ( + + + + )} - Contributors @@ -899,7 +953,6 @@ export function CollectionForm (props){ {formValues.contributors && formValues.contributors.length > 0 && ( <>{renderContribTable()} > )} - Please refer to the contributor file schema information, and this Example TSV File @@ -926,6 +979,15 @@ export function CollectionForm (props){ + {userAdmin === true && !editingCollection.doi_url && ( + handlePublish()} + variant="contained"> + Publish + + )} + handleSubmit()} diff --git a/src/src/components/collections/epicollections.jsx b/src/src/components/collections/epicollections.jsx index dd41472d..3f787ee5 100644 --- a/src/src/components/collections/epicollections.jsx +++ b/src/src/components/collections/epicollections.jsx @@ -4,6 +4,7 @@ import "../../App.css"; import SearchComponent from "../search/SearchComponent"; import {COLUMN_DEF_MIXED,COLUMN_DEF_MIXED_SM,COLUMN_DEF_COLLECTION} from "../search/table_constants"; import { entity_api_get_entity,entity_api_create_entity, entity_api_update_entity} from '../../service/entity_api'; +import {ingest_api_publish_collection,ingest_api_user_admin} from '../../service/ingest_api'; import { getPublishStatusColor } from "../../utils/badgeClasses"; import { generateDisplaySubtypeSimple_UBKG } from "../../utils/display_subtypes"; import Papa from 'papaparse'; @@ -15,6 +16,8 @@ import Dialog from "@material-ui/core/Dialog"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import GroupModal from "../uuid/groupModal"; +import LoadingButton from '@mui/lab/LoadingButton'; +import {ErrBox} from "../../utils/ui_elements"; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; @@ -51,17 +54,26 @@ export function EPICollectionForm (props){ var [fileDetails, setFileDetails] = useState(); var [buttonState, setButtonState] = useState(''); var [warningOpen, setWarningOpen] = React.useState(false); - var [openGroupModal, setOpenGroupModal] = useState(false - - - ); + var [openGroupModal, setOpenGroupModal] = useState(false ); var [lookupShow, setLookupShow] = useState(false); var [loadingDatasets, setLoadingDatasets] = useState(true); var [hideUUIDList, setHideUUIDList] = useState(true); var [loadUUIDList, setLoadUUIDList] = useState(false); var [validatingSubmitForm, setValidatingSubmitForm] = useState(false); var [entityInfo, setEntityInfo] = useState(); + var [userAdmin, setUserAdmin] = useState(false); var [pageError, setPageError] = useState(""); + var [publishing, setPublishing] = useState(false); +// var [publishError, setPublishError] = useState({ + // status:"", + // message:"", + // }); + // @TODO: See what we can globalize/memoize/notize here + var [errorHandler, setErrorHandler] = useState({ + status: "", + message: "", + isError: null + }); var [formWarnings, setFormWarnings] = useState({ bulk_dataset_uuids:"" }); @@ -87,6 +99,18 @@ export function EPICollectionForm (props){ var [datatypeList] = useState(props.dtl_all); var [editingCollection] = useState(props.editingCollection); + + useEffect(() => { + ingest_api_user_admin(JSON.parse(localStorage.getItem("info")).groups_token) + .then((results) => { + console.debug('%c◉ ADMINCHECK ', 'color:#3F007b', results); + setUserAdmin(results) + }) + .catch((err) => { + console.debug('%c⭗', 'color:#1f005d', "ingest_api_user_admin ERR", err ); + }) + }, []); + useEffect(() => { if (editingCollection) { setassociatedEntities([]) @@ -462,6 +486,30 @@ export function EPICollectionForm (props){ }); } + + + const handlePublish = () => { + setPublishing(true) + ingest_api_publish_collection(props.authToken,editingCollection.uuid) + .then((response) => { + console.debug('%c◉ PUBLISHED ', 'color:#00ff7b', ); + // props.onProcessed(response); + if(response.status === 200){ + console.debug('%c◉ Good ingest_api_publish_collection ', 'color:#00ff7b', response); + props.onProcessed(response.results); + }else{ + console.debug('%c◉ ingest_api_publish_collection Bad result', 'color:#ff337b', response); + setPublishing(false) + let authMessage = response.status === 401 ? "User must be Authorized" : response.results.error.toString(); + setPageError(response.status + " | " + authMessage); + } + }) + .catch((error) => { + console.debug('%c⭗ handlePublishErr Broken Result', 'color:#ff005d', error); + setPageError(error.status + " | " + error.message); + setPublishing(false); + }); + } const handleUpdate = (formSubmit) => { // Need to only pass what's changed now @@ -890,6 +938,18 @@ export function EPICollectionForm (props){ value={formValues.title} /> + {editingCollection && editingCollection.doi_url && ( + + + + )} + {userAdmin === true && !editingCollection.doi_url && ( + handlePublish()} + variant="contained"> + Publish + + )} handleSubmit()} diff --git a/src/src/service/ingest_api.js b/src/src/service/ingest_api.js index d77ed1ff..c6f8e02c 100644 --- a/src/src/service/ingest_api.js +++ b/src/src/service/ingest_api.js @@ -12,7 +12,6 @@ import FormData from "form-data"; export function ingest_api_users_groups(auth) { const options = {headers:{Authorization: "Bearer " + auth, "Content-Type":"application/json"}}; - return axios .get( `${process.env.REACT_APP_METADATA_API_URL}/metadata/usergroups`, options) @@ -44,6 +43,40 @@ export function ingest_api_users_groups(auth) { } +/* + * Is User Admin + * + */ +export function ingest_api_user_admin(auth) { + const options = {headers:{Authorization: "Bearer " + auth, + "Content-Type":"application/json"}}; + return axios + .get( + `${process.env.REACT_APP_METADATA_API_URL}/metadata/usergroups`, options) + .then(res => { + + console.debug('%c◉ res ', 'color:#00ff7b', res); + let groups = res.data.groups; + console.debug('%c◉ ADMIN ', 'color:#FF227b', groups); + + for (let group in groups) { + let groupName = groups[group].name + if(groupName.includes("hubmap-data-admin")){ + return true + }else{ + return false + } + } + + + }) + .catch(error => { + console.debug("ERR ingest_api_users_groups", error, error.response); + return {error} + }); +} + + /* * Upload a file @@ -533,3 +566,29 @@ export function ingest_api_upload_bulk_metadata(type, dataFile, auth) { return {error} }); }; + + + +/* + * Notify + * + */ +export function ingest_api_publish_collection(auth, data) { + const options = {headers:{Authorization: "Bearer " + auth,"Content-Type":"application/json"}}; + let url = `${process.env.REACT_APP_DATAINGEST_API_URL}/collections/${data}/register-doi`; + console.debug('%c◉ publish ', 'color:#00ff7b', url,options); + return axios + .put(url, data, options) + .then(res => { + let results = res.data; + return {status:res.status, results:results} + }) + .catch(error => { + if(error.response){ + return {status:error.response.status, results:error.response.data} + }else{ + return {error} + } + }); +}; +