UNPKG

@finos/legend-application-marketplace

Version:
358 lines 24.9 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; /** * Copyright (c) 2020-present, Goldman Sachs * * Licensed 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 { useSearchParams } from '@finos/legend-application/browser'; import { V1_AccessPointGroupReference, V1_ApprovalType, } from '@finos/legend-graph'; import { DataGrid, } from '@finos/legend-lego/data-grid'; import { LegendUser } from '@finos/legend-shared'; import { Box, Button, Checkbox, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, Tooltip, } from '@mui/material'; import { useEffect, useMemo, useState } from 'react'; import { EntitlementsDataContractViewer } from './EntitlementsDataContractViewer.js'; import { EntitlementsDataContractViewerState } from '../../../stores/lakehouse/entitlements/EntitlementsDataContractViewerState.js'; import { useLegendMarketplaceBaseStore } from '../../../application/LegendMarketplaceFrameworkProvider.js'; import { CubesLoadingIndicator, CubesLoadingIndicatorIcon, InfoCircleIcon, UserDisplay, } from '@finos/legend-art'; import { getUserById } from '../../../stores/lakehouse/LakehouseUtils.js'; import { flowResult } from 'mobx'; import { useAuth } from 'react-oidc-context'; import { observer } from 'mobx-react-lite'; const UserCellRenderer = (props) => { const { userId, userDataMap, setUserDataMap, navigationService, userSearchService, userProfileImageUrl, applicationDirectoryUrl, } = props; const [isLoading, setIsLoading] = useState(false); const userData = userId ? userDataMap.get(userId) : undefined; useEffect(() => { const fetchUserData = async (_userId) => { setIsLoading(true); try { const fetchedUserData = userSearchService ? ((await getUserById(_userId, userSearchService)) ?? _userId) : _userId; setUserDataMap((prev) => { const newMap = new Map(prev); newMap.set(_userId, fetchedUserData); return newMap; }); } finally { setIsLoading(false); } }; if (userId && userData === undefined) { // eslint-disable-next-line no-void void fetchUserData(userId); } }, [setUserDataMap, userData, userId, userSearchService]); if (isLoading) { return _jsx(CircularProgress, { size: 20 }); } else if (userData instanceof LegendUser) { const imgSrc = userProfileImageUrl?.replace('{userId}', userData.id); const openUserDirectoryLink = () => navigationService.navigator.visitAddress(`${applicationDirectoryUrl}/${userId}`); return (_jsx(UserDisplay, { user: userData, imgSrc: imgSrc, onClick: () => openUserDirectoryLink(), className: "marketplace-lakehouse-entitlements__grid__user-display" })); } else if (userData) { return _jsx(_Fragment, { children: userData }); } else { return _jsx(_Fragment, { children: userId }); } }; const EntitlementsDashboardActionModal = (props) => { const { open, selectedTasks, dashboardState, onClose, action, allContracts, userDataMap, navigationService, userProfileImageUrl, applicationDirectoryUrl, } = props; const auth = useAuth(); const [isLoading, setIsLoading] = useState(false); const [errorMessages, setErrorMessages] = useState([]); const [successCount, setSuccessCount] = useState(0); const handleClose = () => { setIsLoading(false); setErrorMessages([]); setSuccessCount(0); onClose(); }; const actionFunction = action === 'approve' ? dashboardState.approve.bind(dashboardState) : dashboardState.deny.bind(dashboardState); const handleAction = async () => { setIsLoading(true); const currentErrorMessages = []; await Promise.all(Array.from(selectedTasks).map(async (task) => { return flowResult(actionFunction(task, auth.user?.access_token)) .then(() => setSuccessCount((prev) => prev++)) .catch((error) => currentErrorMessages.push([task, error.message])); })); setIsLoading(false); // If everything was successful, show a success message and close the modal. if (currentErrorMessages.length === 0) { dashboardState.lakehouseEntitlementsStore.applicationStore.notificationService.notifySuccess(`${selectedTasks.length} selected contract requests have been ${action === 'approve' ? 'approved' : 'denied'} successfully.`); handleClose(); } else { // If there were errors, we won't close the modal and will show the errors in the modal. setErrorMessages(currentErrorMessages); } }; if (action === undefined) { return null; } return (_jsxs(Dialog, { open: open, onClose: handleClose, fullWidth: true, maxWidth: "md", children: [_jsxs(DialogTitle, { children: [action === 'approve' ? 'Approve' : 'Deny', " Contract Requests"] }), _jsxs(DialogContent, { className: "marketplace-lakehouse-entitlements__data-contract-approval__content", children: [_jsx(CubesLoadingIndicator, { isLoading: isLoading, children: _jsx(CubesLoadingIndicatorIcon, {}) }), !isLoading && errorMessages.length === 0 && (_jsxs("div", { children: [action === 'approve' ? 'Approve' : 'Deny', " ", selectedTasks.length, ' ', "selected contract requests"] })), !isLoading && errorMessages.length > 0 && (_jsxs(_Fragment, { children: [successCount > 0 && (_jsxs(Box, { className: "marketplace-lakehouse-entitlements__data-contract-approval__success", children: [successCount, " selected contract requests were", ' ', action === 'approve' ? 'approved' : 'denied', " successfully"] })), errorMessages.map(([task, errorMessage]) => { const contractId = task.dataContractId; const resource = allContracts.find((contract) => contract.guid === contractId)?.resource; const dataProduct = resource instanceof V1_AccessPointGroupReference ? resource.dataProduct.name : 'unknown'; const accessPointGroup = resource instanceof V1_AccessPointGroupReference ? resource.accessPointGroup : 'unknown'; const userData = userDataMap.get(task.consumer); const userComponent = userData instanceof LegendUser ? (_jsx(UserDisplay, { user: userData, imgSrc: userProfileImageUrl?.replace('{userId}', userData.id), onClick: () => navigationService.navigator.visitAddress(`${applicationDirectoryUrl}/${userData.id}`) })) : (_jsx(_Fragment, { children: task.consumer })); return (_jsxs(Box, { className: "marketplace-lakehouse-entitlements__data-contract-approval__error", children: [_jsxs("div", { className: "marketplace-lakehouse-entitlements__data-contract-approval__error__content", children: ["Encountered an error", ' ', action === 'approve' ? 'approving' : 'denying', " request for", ' ', _jsx("div", { className: "marketplace-lakehouse-entitlements__data-contract-approval__error__user", children: userComponent }), ' ', "for Access Point Group", ' ', _jsx("span", { className: "marketplace-lakehouse-text__emphasis", children: accessPointGroup }), ' ', "on Data Product", ' ', _jsx("span", { className: "marketplace-lakehouse-text__emphasis", children: dataProduct }), ":"] }), _jsx("div", { children: _jsx("code", { children: errorMessage }) })] }, task.taskId)); })] }))] }), _jsxs(DialogActions, { children: [_jsxs(Button, { onClick: () => { // eslint-disable-next-line no-void void handleAction(); }, variant: "contained", disabled: isLoading || errorMessages.length > 0, color: action === 'approve' ? 'success' : 'error', children: [action === 'approve' ? 'Approve' : 'Deny', " Selected Contracts"] }), _jsx(Button, { onClick: handleClose, variant: "outlined", disabled: isLoading, children: "Cancel" })] })] })); }; export const EntitlementsPendingTasksDashbaord = observer((props) => { const { dashboardState } = props; const tasks = dashboardState.pendingTasks; const allContracts = dashboardState.allContracts; const privilegeManagerTasks = tasks?.filter((task) => task.type === V1_ApprovalType.CONSUMER_PRIVILEGE_MANAGER_APPROVAL) ?? []; const dataOwnerTasks = tasks?.filter((task) => task.type === V1_ApprovalType.DATA_OWNER_APPROVAL) ?? []; const otherTasks = tasks?.filter((task) => !privilegeManagerTasks.includes(task) && !dataOwnerTasks.includes(task)) ?? []; const marketplaceBaseStore = useLegendMarketplaceBaseStore(); const [searchParams, setSearchParams] = useSearchParams(); const [selectedAction, setSelectedAction] = useState(); const [userDataMap, setUserDataMap] = useState(new Map()); const [selectedTaskIdsSet, setSelectedTaskIdsSet] = useState(new Set(searchParams .get('selectedTasks') ?.split(',') .filter((taskId) => tasks?.map((task) => task.taskId).includes(taskId)) ?? [])); const [selectedContract, setSelectedContract] = useState(); useEffect(() => { setSearchParams((params) => { if (selectedTaskIdsSet.size === 0) { params.delete('selectedTasks'); } else { params.set('selectedTasks', Array.from(selectedTaskIdsSet.values()).join(',')); } return params; }); }, [selectedTaskIdsSet, setSearchParams]); const handleFirstDataRendered = (event) => { const nodesToSelect = []; event.api.forEachNode((node) => { if (node.data && selectedTaskIdsSet.has(node.data.taskId)) { nodesToSelect.push(node); } }); event.api.setNodesSelected({ nodes: nodesToSelect, newValue: true }); }; const handleCellClicked = (event) => { if (event.colDef.colId !== 'selection' && event.colDef.colId !== 'targetUser' && event.colDef.colId !== 'requester') { const contract = allContracts?.find((_contract) => _contract.guid === event.data?.dataContractId); setSelectedContract(contract); } }; const rowSelection = useMemo(() => ({ mode: 'multiRow', checkboxes: false, headerCheckbox: false }), []); const CustomSelectionRenderer = (params) => { const handleChange = (_) => { setSelectedTaskIdsSet((prev) => { if (params.data) { const newSet = new Set(prev); if (prev.has(params.data.taskId)) { newSet.delete(params.data.taskId); } else { newSet.add(params.data.taskId); } return newSet; } return prev; }); }; return (_jsx(Checkbox, { size: "large", checked: selectedTaskIdsSet.has(params.data?.taskId ?? ''), onChange: handleChange, sx: { padding: 0 } })); }; const CustomSelectionHeaderRenderer = (_props) => { const { taskSet } = _props; const checked = taskSet.every((task) => selectedTaskIdsSet.has(task.taskId)); const indeterminate = !checked && taskSet.some((task) => selectedTaskIdsSet.has(task.taskId)); const handleChange = (e) => { if (!checked || indeterminate) { setSelectedTaskIdsSet((prev) => { const newSet = new Set(prev); taskSet.forEach((task) => newSet.add(task.taskId)); return newSet; }); } else { setSelectedTaskIdsSet((prev) => { const newSet = new Set(prev); taskSet.forEach((task) => newSet.delete(task.taskId)); return newSet; }); } }; return (_jsx(Checkbox, { size: "large", checked: checked, indeterminate: indeterminate, onChange: handleChange, sx: { padding: 0 } })); }; const colDefs = [ { minWidth: 50, sortable: true, resizable: true, headerName: 'Action Date', flex: 1, cellRenderer: (params) => { const taskType = params.data?.eventPayload.type; const timestamp = params.data?.eventPayload.eventTimestamp; return (_jsxs(_Fragment, { children: [taskType, ": ", timestamp] })); }, }, { minWidth: 50, sortable: true, resizable: true, colId: 'targetUser', headerName: 'Target User', flex: 1, cellRenderer: (params) => { return (_jsx(UserCellRenderer, { userId: params.data?.consumer, userDataMap: userDataMap, setUserDataMap: setUserDataMap, navigationService: dashboardState.lakehouseEntitlementsStore.applicationStore .navigationService, userSearchService: marketplaceBaseStore.userSearchService, userProfileImageUrl: marketplaceBaseStore.applicationStore.config .marketplaceUserProfileImageUrl, applicationDirectoryUrl: marketplaceBaseStore.applicationStore.config .lakehouseEntitlementsConfig?.applicationDirectoryUrl })); }, }, { minWidth: 50, sortable: true, resizable: true, colId: 'requester', headerName: 'Requester', flex: 1, cellRenderer: (params) => { const contractId = params.data?.dataContractId; const requester = allContracts?.find((contract) => contract.guid === contractId)?.createdBy; return requester ? (_jsx(UserCellRenderer, { userId: requester, userDataMap: userDataMap, setUserDataMap: setUserDataMap, navigationService: dashboardState.lakehouseEntitlementsStore.applicationStore .navigationService, userSearchService: marketplaceBaseStore.userSearchService, userProfileImageUrl: marketplaceBaseStore.applicationStore.config .marketplaceUserProfileImageUrl, applicationDirectoryUrl: marketplaceBaseStore.applicationStore.config .lakehouseEntitlementsConfig?.applicationDirectoryUrl })) : (_jsx(_Fragment, { children: "Unknown" })); }, }, { minWidth: 50, sortable: true, resizable: true, headerName: 'Target Data Product', flex: 1, cellRenderer: (params) => { const contractId = params.data?.dataContractId; const resource = allContracts?.find((contract) => contract.guid === contractId)?.resource; const dataProduct = resource instanceof V1_AccessPointGroupReference ? resource.dataProduct : undefined; return _jsx(_Fragment, { children: dataProduct?.name ?? 'Unknown' }); }, }, { minWidth: 50, sortable: true, resizable: true, headerName: 'Target Access Point Group', flex: 1, cellRenderer: (params) => { const contractId = params.data?.dataContractId; const resource = allContracts?.find((contract) => contract.guid === contractId)?.resource; const accessPointGroup = resource instanceof V1_AccessPointGroupReference ? resource.accessPointGroup : undefined; return _jsx(_Fragment, { children: accessPointGroup ?? 'Unknown' }); }, }, { minWidth: 50, sortable: true, resizable: true, headerName: 'Business Justification', flex: 2, cellRenderer: (params) => { const contractId = params.data?.dataContractId; const businessJustification = allContracts?.find((contract) => contract.guid === contractId)?.description; return _jsx(_Fragment, { children: businessJustification ?? 'Unknown' }); }, }, { minWidth: 50, sortable: true, resizable: true, hide: true, headerName: 'Contract ID', flex: 2, cellRenderer: (params) => { return _jsx(_Fragment, { children: params.data?.dataContractId ?? 'Unknown' }); }, }, ]; return (_jsxs(_Fragment, { children: [_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks", children: [_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__action-btns", children: [_jsxs(Button, { variant: "contained", color: "success", disabled: !selectedTaskIdsSet.size, onClick: () => setSelectedAction('approve'), children: ["Approve ", selectedTaskIdsSet.size, " tasks"] }), _jsxs(Button, { variant: "contained", color: "error", disabled: !selectedTaskIdsSet.size, onClick: () => setSelectedAction('deny'), children: ["Deny ", selectedTaskIdsSet.size, " tasks"] })] }), _jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grids", children: [privilegeManagerTasks.length > 0 && (_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid-container", children: [_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid__header", children: ["Privilege Manager Approvals", _jsx(Tooltip, { className: "marketplace-lakehouse-entitlements__pending-tasks__tooltip__icon", title: "These are pending requests for which you are listed as a Privilege Manager.", slotProps: { tooltip: { className: 'marketplace-lakehouse-entitlements__pending-tasks__tooltip', }, }, children: _jsx(InfoCircleIcon, {}) })] }), _jsx(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid ag-theme-balham", children: _jsx(DataGrid, { rowData: privilegeManagerTasks, onRowDataUpdated: (params) => { params.api.refreshCells({ force: true }); }, suppressFieldDotNotation: true, suppressContextMenu: false, rowHeight: 45, rowSelection: rowSelection, onFirstDataRendered: handleFirstDataRendered, onCellClicked: handleCellClicked, columnDefs: [ { headerName: '', colId: 'selection', width: 50, cellRenderer: CustomSelectionRenderer, headerComponent: (params) => (_jsx(CustomSelectionHeaderRenderer, { params: params, taskSet: privilegeManagerTasks })), pinned: 'left', }, ...colDefs, ] }) })] })), dataOwnerTasks.length > 0 && (_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid-container", children: [_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid__header", children: ["Data Owner Approvals", _jsx(Tooltip, { className: "marketplace-lakehouse-entitlements__pending-tasks__tooltip__icon", title: "These are pending requests for which you are listed as a Data Owner.", slotProps: { tooltip: { className: 'marketplace-lakehouse-entitlements__pending-tasks__tooltip', }, }, children: _jsx(InfoCircleIcon, {}) })] }), _jsx(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid ag-theme-balham", children: _jsx(DataGrid, { rowData: dataOwnerTasks, onRowDataUpdated: (params) => { params.api.refreshCells({ force: true }); }, suppressFieldDotNotation: true, suppressContextMenu: false, rowHeight: 45, rowSelection: rowSelection, onFirstDataRendered: handleFirstDataRendered, onCellClicked: handleCellClicked, columnDefs: [ { headerName: '', colId: 'selection', width: 50, cellRenderer: CustomSelectionRenderer, headerComponent: (params) => (_jsx(CustomSelectionHeaderRenderer, { params: params, taskSet: dataOwnerTasks })), pinned: 'left', }, ...colDefs, ] }) })] })), otherTasks.length > 0 && (_jsxs(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid-container", children: [_jsx(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid__header", children: "Other Approvals" }), _jsx(Box, { className: "marketplace-lakehouse-entitlements__pending-tasks__grid ag-theme-balham", children: _jsx(DataGrid, { rowData: otherTasks, onRowDataUpdated: (params) => { params.api.refreshCells({ force: true }); }, suppressFieldDotNotation: true, suppressContextMenu: false, rowHeight: 45, rowSelection: rowSelection, onFirstDataRendered: handleFirstDataRendered, onCellClicked: handleCellClicked, columnDefs: [ { headerName: '', colId: 'selection', width: 50, cellRenderer: CustomSelectionRenderer, headerComponent: (params) => (_jsx(CustomSelectionHeaderRenderer, { params: params, taskSet: otherTasks })), pinned: 'left', }, ...colDefs, ] }) })] }))] })] }), _jsx(EntitlementsDashboardActionModal, { open: selectedAction !== undefined, selectedTasks: tasks?.filter((task) => selectedTaskIdsSet.has(task.taskId)) ?? [], dashboardState: dashboardState, onClose: () => setSelectedAction(undefined), action: selectedAction, allContracts: allContracts ?? [], userDataMap: userDataMap, navigationService: dashboardState.lakehouseEntitlementsStore.applicationStore .navigationService, userProfileImageUrl: marketplaceBaseStore.applicationStore.config .marketplaceUserProfileImageUrl, applicationDirectoryUrl: marketplaceBaseStore.applicationStore.config .lakehouseEntitlementsConfig?.applicationDirectoryUrl }), selectedContract !== undefined && (_jsx(EntitlementsDataContractViewer, { open: true, currentViewer: new EntitlementsDataContractViewerState(selectedContract, marketplaceBaseStore.lakehouseContractServerClient), onClose: () => setSelectedContract(undefined) }))] })); }); //# sourceMappingURL=EntitlementsPendingTasksDashboard.js.map