| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import React, { useRef, useCallback, useState, useEffect } from "react"; |
| import { useSearchParams, useNavigate, useLocation } from "react-router-dom"; |
| import XATableLayout from "../../../components/XATableLayout"; |
| import dateFormat from "dateformat"; |
| import { fetchApi } from "../../../utils/fetchAPI"; |
| import { toast } from "react-toastify"; |
| import moment from "moment-timezone"; |
| import viewRequestIcon from "../../../images/view-request.svg"; |
| |
| import { |
| getTableSortBy, |
| getTableSortType, |
| serverError, |
| parseSearchFilter, |
| isSystemAdmin |
| } from "../../../utils/XAUtils"; |
| import { Button, Modal } from "react-bootstrap"; |
| |
| const DatashareInDatasetListComp = ({ |
| id, |
| type, |
| shareStatus, |
| setUpdateTable, |
| updateTable, |
| userAclPerm, |
| searchFilter, |
| fetchShareStatusMetrics |
| }) => { |
| const { state } = useLocation(); |
| const [requestListData, setRequestListData] = useState([]); |
| const [loader, setLoader] = useState(true); |
| const [entries, setEntries] = useState([]); |
| const fetchIdRef = useRef(0); |
| const navigate = useNavigate(); |
| |
| const [totalCount, setTotalCount] = useState(0); |
| const [resetPage, setResetpage] = useState({ page: 0 }); |
| |
| const [pageCount, setPageCount] = useState( |
| state && state.showLastPage ? state.addPageData.totalPage : 0 |
| ); |
| const [currentpageIndex, setCurrentPageIndex] = useState( |
| state && state.showLastPage ? state.addPageData.totalPage - 1 : 0 |
| ); |
| const [currentpageSize, setCurrentPageSize] = useState( |
| state && state.showLastPage ? state.addPageData.pageSize : 25 |
| ); |
| const [searchFilterParams, setSearchFilterParams] = useState([]); |
| const [searchParams, setSearchParams] = useSearchParams(); |
| const [deleteDatashareReqInfo, setDeleteDatashareReqInfo] = useState({}); |
| const [ |
| showDatashareRequestDeleteConfirmModal, |
| setShowDatashareRequestDeleteConfirmModal |
| ] = useState(false); |
| const [defaultSearchFilterParams, setDefaultSearchFilterParams] = useState( |
| [] |
| ); |
| const [pageLoader, setPageLoader] = useState(true); |
| |
| const fetchRequestList = useCallback( |
| async ({ pageSize, pageIndex, sortBy, gotoPage }) => { |
| setLoader(true); |
| let resp = []; |
| let requestList = []; |
| let totalCount = 0; |
| let page = |
| state && state.showLastPage |
| ? state.addPageData.totalPage - 1 |
| : pageIndex; |
| let totalPageCount = 0; |
| const fetchId = ++fetchIdRef.current; |
| let params = { ...searchFilter }; |
| if (fetchId === fetchIdRef.current) { |
| params["pageSize"] = 999999999; |
| if (sortBy.length > 0) { |
| if (getTableSortBy(sortBy) == "name") |
| params["sortBy"] = "datasetName"; |
| else params["sortBy"] = getTableSortBy(sortBy); |
| |
| params["sortType"] = getTableSortType(sortBy); |
| } |
| if (type == "dataset") { |
| params["datasetId"] = id; |
| try { |
| resp = await fetchApi({ |
| url: "gds/datashare/summary", |
| params: params |
| }); |
| if (resp.data.list.length > 0) { |
| requestList = resp.data.list; |
| requestList?.forEach((datashare) => { |
| for (let i = 0; i < datashare.datasets.length; i++) { |
| if (datashare.datasets[i].datasetId == id) { |
| datashare.shareStatus = datashare.datasets[i].shareStatus; |
| datashare.requestId = datashare.datasets[i].id; |
| datashare.datasetName = datashare.datasets[i].datasetName; |
| break; |
| } |
| } |
| }); |
| totalCount = requestList != undefined ? requestList.length : 0; |
| } |
| } catch (error) { |
| serverError(error); |
| console.error( |
| `Error occurred while fetching Datashare request list! ${error}` |
| ); |
| } |
| if (shareStatus != undefined) { |
| let tempReqList = requestList; |
| requestList = []; |
| tempReqList?.forEach((request) => { |
| if (request.shareStatus == shareStatus) { |
| requestList.push(request); |
| } |
| }); |
| totalCount = requestList.length; |
| } |
| } else if (type == "datashare") { |
| params["dataShareId"] = id; |
| try { |
| resp = await fetchApi({ |
| url: "gds/dataset/summary", |
| params: params |
| }); |
| if (resp.data.list.length > 0) { |
| requestList = resp.data.list; |
| requestList?.forEach((dataset) => { |
| for (let i = 0; i < dataset.dataShares.length; i++) { |
| if (dataset.dataShares[i].dataShareId == id) { |
| dataset.shareStatus = dataset.dataShares[i].shareStatus; |
| dataset.requestId = dataset.dataShares[i].id; |
| dataset.dataShareName = dataset.dataShares[i].dataShareName; |
| dataset.approver = dataset.dataShares[i].approver; |
| break; |
| } |
| } |
| }); |
| totalCount = requestList != undefined ? requestList.length : 0; |
| } |
| } catch (error) { |
| serverError(error); |
| console.error( |
| `Error occurred while fetching Dataset request list! ${error}` |
| ); |
| } |
| if (shareStatus != undefined) { |
| let tempReqList = requestList; |
| requestList = []; |
| tempReqList?.forEach((request) => { |
| if (request.shareStatus == shareStatus) { |
| requestList.push(request); |
| } |
| }); |
| totalCount = requestList.length; |
| } |
| } |
| resp.data.totalCount = totalCount; |
| console.log("Total count: " + totalCount); |
| params["pageSize"] = pageSize; |
| let startIndex = |
| state && state.showLastPage |
| ? (state.addPageData.totalPage - 1) * pageSize |
| : pageIndex * pageSize; |
| let endIndex = startIndex + pageSize; |
| requestList = requestList.slice(startIndex, endIndex); |
| // if (sortBy.length > 0) { |
| // params["sortBy"] = getTableSortBy(sortBy); |
| // params["sortType"] = getTableSortType(sortBy); |
| // } |
| //setUpdateTable(moment.now()); |
| |
| setTotalCount(totalCount); |
| setRequestListData(requestList); |
| setEntries(resp.data); |
| setCurrentPageIndex(page); |
| setCurrentPageSize(pageSize); |
| setPageCount(Math.ceil(totalCount / pageSize)); |
| //setResdatasetReqColumnsetpage({ page: gotoPage }); |
| setLoader(false); |
| } |
| }, |
| [searchFilter, updateTable] |
| ); |
| |
| useEffect(() => { |
| let searchFilterParam = {}; |
| let searchParam = {}; |
| let defaultSearchFilterParam = []; |
| |
| // Get Search Filter Params from current search params |
| const currentParams = Object.fromEntries([...searchParams]); |
| for (const param in currentParams) { |
| let category = param; |
| let value = currentParams[param]; |
| searchFilterParam[category] = value; |
| defaultSearchFilterParam.push({ |
| category: category, |
| value: value |
| }); |
| } |
| |
| // Updating the states for search params, search filter and default search filter |
| setSearchParams({ ...currentParams, ...searchParam }); |
| if ( |
| JSON.stringify(searchFilterParams) !== JSON.stringify(searchFilterParam) |
| ) { |
| setSearchFilterParams(searchFilterParam); |
| } |
| setDefaultSearchFilterParams(defaultSearchFilterParam); |
| setPageLoader(false); |
| localStorage.setItem("newDataAdded", state && state.showLastPage); |
| }, [searchParams]); |
| |
| const searchFilterOptions = [ |
| { |
| category: "dataShareNamePartial", |
| label: "Datashare Name", |
| urlLabel: "dataShareNamePartial", |
| type: "text" |
| } |
| ]; |
| |
| const updateSearchFilter = (filter) => { |
| let { searchFilterParam, searchParam } = parseSearchFilter( |
| filter, |
| searchFilterOptions |
| ); |
| |
| setSearchFilterParams(searchFilterParam); |
| }; |
| |
| const datasetReqColumns = React.useMemo( |
| () => [ |
| { |
| Header: "Name", |
| accessor: "name", |
| //width: 200, |
| Cell: (val) => { |
| return ( |
| <span |
| className="text-truncate" |
| title={val.value} |
| style={{ maxWidth: "240px", display: "inline-block" }} |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Status", |
| accessor: "shareStatus", |
| width: 108, |
| disableSortBy: true, |
| Cell: (val) => { |
| return ( |
| <span |
| className={ |
| val.value === "REQUESTED" |
| ? "badge badge-light gds-requested-status" |
| : val.value === "GRANTED" |
| ? "badge badge-light gds-granted-status" |
| : val.value === "ACTIVE" |
| ? "badge badge-light gds-active-status" |
| : "badge badge-light gds-denied-status" |
| } |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Last Updated", |
| accessor: "updateTime", |
| Cell: (rawValue) => { |
| return dateFormat(rawValue.value, "mm/dd/yyyy"); |
| }, |
| width: 108, |
| disableResizing: true, |
| getResizerProps: () => {} |
| }, |
| { |
| Header: "Approver", |
| accessor: "approver", |
| Cell: (rawValue) => { |
| return ( |
| <div className="position-relative text-center"> |
| <span>{rawValue.value}</span> |
| </div> |
| ); |
| }, |
| width: 108, |
| disableResizing: true, |
| getResizerProps: () => {} |
| }, |
| { |
| Header: "", |
| accessor: "actions", |
| Cell: ({ row: { original } }) => { |
| return ( |
| <div> |
| <Button |
| variant="outline-dark" |
| size="sm" |
| className="mr-2" |
| style={{ height: "31px" }} |
| title="View Request" |
| onClick={() => |
| navigate(`/gds/request/detail/${original.requestId}`) |
| } |
| data-name="viewRequest" |
| data-id={original.requestId} |
| > |
| <img src={viewRequestIcon} height="18px" width="18px" /> |
| </Button> |
| <Button |
| variant="outline-dark" |
| size="sm" |
| className="mr-2" |
| title="View Dataset" |
| onClick={() => navigate(`/gds/dataset/${original.id}/detail`)} |
| data-name="viewDataset" |
| data-id={original.id} |
| > |
| <i className="fa-fw fa fa-eye fa-fw fa fa-large"></i> |
| </Button> |
| |
| <> |
| {(isSystemAdmin() || userAclPerm == "ADMIN") && ( |
| <Button |
| variant="danger" |
| size="sm" |
| title="Delete" |
| onClick={() => |
| toggleConfirmModalForDelete( |
| original.requestId, |
| original.dataShareName, |
| original.name, |
| original.shareStatus |
| ) |
| } |
| data-name="deleteDatashareRequest" |
| data-id={original.id} |
| data-cy={original.id} |
| > |
| <i className="fa-fw fa fa-trash fa-fw fa fa-large" /> |
| </Button> |
| )} |
| </> |
| </div> |
| ); |
| }, |
| disableSortBy: true |
| } |
| ], |
| [] |
| ); |
| |
| const requestColumns = React.useMemo( |
| () => [ |
| { |
| Header: "Name", |
| accessor: "name", |
| //width: 200, |
| Cell: (val) => { |
| return ( |
| <span |
| className="text-truncate" |
| title={val.value} |
| style={{ maxWidth: "140px", display: "inline-block" }} |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Service", |
| accessor: "serviceName", |
| //width: 200, |
| Cell: (val) => { |
| return ( |
| <span |
| className="text-truncate" |
| title={val.value} |
| style={{ maxWidth: "140px", display: "inline-block" }} |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Zone", |
| accessor: "zoneName", |
| // width: 200, |
| Cell: (val) => { |
| return ( |
| <span |
| className="text-truncate" |
| title={val.value} |
| style={{ maxWidth: "140px", display: "inline-block" }} |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Resources", |
| accessor: "resourceCount", |
| width: 100, |
| disableSortBy: true, |
| Cell: (val) => { |
| return ( |
| <span |
| title={val.value} |
| style={{ maxWidth: "240px", display: "inline-block" }} |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Status", |
| accessor: "shareStatus", |
| width: 108, |
| disableSortBy: true, |
| Cell: (val) => { |
| return ( |
| <span |
| className={ |
| val.value === "REQUESTED" |
| ? "badge badge-light gds-requested-status" |
| : val.value === "GRANTED" |
| ? "badge badge-light gds-granted-status" |
| : val.value === "ACTIVE" |
| ? "badge badge-light gds-active-status" |
| : "badge badge-light gds-denied-status" |
| } |
| > |
| {val.value} |
| </span> |
| ); |
| } |
| }, |
| { |
| Header: "Last Updated", |
| accessor: "updateTime", |
| Cell: (rawValue) => { |
| return dateFormat(rawValue.value, "mm/dd/yyyy"); |
| }, |
| width: 108, |
| disableResizing: true, |
| getResizerProps: () => {} |
| }, |
| { |
| Header: "", |
| accessor: "actions", |
| Cell: ({ row: { original } }) => { |
| return ( |
| <div> |
| <Button |
| variant="outline-dark" |
| size="sm" |
| className="mr-2" |
| style={{ height: "31px" }} |
| title="View Request" |
| onClick={() => |
| navigate(`/gds/request/detail/${original.requestId}`) |
| } |
| data-name="viewRequest" |
| data-id={original.dataShareId} |
| > |
| <img src={viewRequestIcon} height="18px" width="18px" /> |
| </Button> |
| <Button |
| variant="outline-dark" |
| size="sm" |
| className="mr-2" |
| title="View Datashare" |
| onClick={() => navigate(`/gds/datashare/${original.id}/detail`)} |
| data-name="viewDatashare" |
| data-id={original.dataShareId} |
| > |
| <i className="fa-fw fa fa-eye fa-fw fa fa-large"></i> |
| </Button> |
| |
| <> |
| {(isSystemAdmin() || userAclPerm == "ADMIN") && ( |
| <Button |
| variant="danger" |
| size="sm" |
| title="Delete" |
| onClick={() => |
| toggleConfirmModalForDelete( |
| original.requestId, |
| original.name, |
| original.datasetName, |
| original.shareStatus |
| ) |
| } |
| data-name="deleteDatashareRequest" |
| data-id={original.id} |
| data-cy={original.id} |
| > |
| <i className="fa-fw fa fa-trash fa-fw fa fa-large" /> |
| </Button> |
| )} |
| </> |
| </div> |
| ); |
| }, |
| disableSortBy: true |
| } |
| ], |
| [] |
| ); |
| |
| const toggleDatashareRequestDelete = () => { |
| setShowDatashareRequestDeleteConfirmModal(false); |
| }; |
| |
| const toggleConfirmModalForDelete = (id, name, datasetName, status) => { |
| let deleteMsg = ""; |
| if (status == "ACTIVE") { |
| deleteMsg = `Do you want to remove Datashare: ${name} from ${datasetName}`; |
| } else { |
| if (type == "datashare") { |
| deleteMsg = `Do you want to delete request of Dataset: ${datasetName}`; |
| } else { |
| deleteMsg = `Do you want to delete request of Datashare: ${name}`; |
| } |
| } |
| let data = { id: id, name: name, status: status, msg: deleteMsg }; |
| setDeleteDatashareReqInfo(data); |
| setShowDatashareRequestDeleteConfirmModal(true); |
| }; |
| |
| const deleteDatashareRequest = async () => { |
| try { |
| setLoader(true); |
| await fetchApi({ |
| url: `gds/datashare/dataset/${deleteDatashareReqInfo.id}`, |
| method: "DELETE" |
| }); |
| let successMsg = ""; |
| if (deleteDatashareReqInfo.status == "ACTIVE") { |
| successMsg = "Success! Datashare removed from dataset successfully"; |
| } else { |
| successMsg = "Success! Datashare request deleted successfully"; |
| } |
| setShowDatashareRequestDeleteConfirmModal(false); |
| toast.success(successMsg); |
| setUpdateTable(moment.now()); |
| fetchShareStatusMetrics(); |
| |
| // fetchDatashareRequestList( |
| // undefined, |
| // dataShareRequestsList.length == 1 |
| // ? requestCurrentPage - 1 |
| // : requestCurrentPage, |
| // false |
| // ); |
| setLoader(false); |
| } catch (error) { |
| let errorMsg = ""; |
| if (deleteDatashareReqInfo.status == "ACTIVE") { |
| errorMsg = "Failed to remove datashare from dataset "; |
| } else { |
| errorMsg = "Failed to delete datashare request "; |
| } |
| setLoader(false); |
| if (error?.response?.data?.msgDesc) { |
| errorMsg += error.response.data.msgDesc; |
| } |
| toast.error(errorMsg); |
| console.error( |
| "Error occurred during deleting Datashare request : " + error |
| ); |
| } |
| }; |
| |
| const getDefaultSort = React.useMemo( |
| () => [ |
| { |
| id: "updateTime", |
| desc: true |
| } |
| ], |
| [] |
| ); |
| |
| return ( |
| <> |
| {type == "dataset" && ( |
| <XATableLayout |
| data={requestListData} |
| columns={requestColumns} |
| fetchData={fetchRequestList} |
| totalCount={entries && entries.totalCount} |
| loading={loader} |
| pageCount={pageCount} |
| getRowProps={(row) => ({ |
| onClick: (e) => { |
| e.stopPropagation(); |
| //rowModal(row); |
| } |
| })} |
| currentpageIndex={currentpageIndex} |
| currentpageSize={currentpageSize} |
| columnHide={false} |
| columnResizable={false} |
| columnSort={true} |
| defaultSort={getDefaultSort} |
| /> |
| )} |
| |
| {type == "datashare" && ( |
| <XATableLayout |
| data={requestListData} |
| columns={datasetReqColumns} |
| fetchData={fetchRequestList} |
| totalCount={entries && entries.totalCount} |
| loading={loader} |
| pageCount={pageCount} |
| getRowProps={(row) => ({ |
| onClick: (e) => { |
| e.stopPropagation(); |
| //rowModal(row); |
| } |
| })} |
| currentpageIndex={currentpageIndex} |
| currentpageSize={currentpageSize} |
| columnHide={false} |
| columnResizable={false} |
| columnSort={true} |
| defaultSort={getDefaultSort} |
| /> |
| )} |
| |
| <Modal |
| show={showDatashareRequestDeleteConfirmModal} |
| onHide={toggleDatashareRequestDelete} |
| > |
| <Modal.Header closeButton> |
| <h3 className="gds-header bold">{deleteDatashareReqInfo.msg}</h3> |
| </Modal.Header> |
| <Modal.Footer> |
| <Button |
| variant="secondary" |
| size="sm" |
| onClick={() => toggleDatashareRequestDelete()} |
| > |
| No |
| </Button> |
| <Button |
| variant="primary" |
| size="sm" |
| onClick={() => deleteDatashareRequest()} |
| > |
| Yes |
| </Button> |
| </Modal.Footer> |
| </Modal> |
| </> |
| ); |
| }; |
| |
| export default DatashareInDatasetListComp; |