@finos/legend-application-marketplace
Version:
Legend Marketplace application core
358 lines • 24.9 kB
JavaScript
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