@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
222 lines (220 loc) • 8.58 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from 'react';
import useSpreadState from '../../hooks/useSpreadState';
import useActiveSiteId from '../../hooks/useActiveSiteId';
import { fetchPublishingHistoryPackageItems } from '../../services/dashboard';
import { FormattedMessage } from 'react-intl';
import DialogContent from '@mui/material/DialogContent';
import { LoadingState } from '../LoadingState';
import Typography from '@mui/material/Typography';
import { EmptyState } from '../EmptyState';
import List from '@mui/material/List';
import ItemDisplay from '../ItemDisplay';
import { EnhancedDialog } from '../EnhancedDialog';
import { Pager } from '../DashletCard/dashletCommons';
import Box from '@mui/material/Box';
import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
import { useDispatch } from 'react-redux';
import { getOffsetLeft, getOffsetTop } from '@mui/material/Popover';
import { showItemMegaMenu } from '../../state/actions/dialogs';
import { getNumOfMenuOptionsForItem, parseSandBoxItemToDetailedItem } from '../../utils/content';
import ListItemButton from '@mui/material/ListItemButton';
import DialogFooter from '../DialogFooter';
import ApiResponseErrorState from '../ApiResponseErrorState';
const dialogContentHeight = 420;
export function PackageDetailsDialog(props) {
const { packageId, ...enhancedDialogProps } = props;
const site = useActiveSiteId();
const [state, setState] = useSpreadState({
items: null,
loading: false,
error: null,
total: null,
limit: 10,
offset: 0
});
const currentPage = state.offset / state.limit;
const totalPages = state.total ? Math.ceil(state.total / state.limit) : 0;
const dispatch = useDispatch();
const [over, setOver] = useState(null);
useEffect(() => {
if (packageId) {
setState({ items: null, loading: true, error: null });
fetchPublishingHistoryPackageItems(site, packageId, {
limit: state.limit,
offset: 0
}).subscribe({
next: (items) => {
setState({ items, loading: false, offset: 0, total: items.total });
},
error({ response }) {
setState({ error: response.response, loading: false });
}
});
}
}, [packageId, site, setState, state.limit]);
const onOpenMenu = (element, item) => {
const anchorRect = element.getBoundingClientRect();
const top = anchorRect.top + getOffsetTop(anchorRect, 'top');
const left = anchorRect.left + getOffsetLeft(anchorRect, 'left');
dispatch(
showItemMegaMenu({
path: item.path,
anchorReference: 'anchorPosition',
anchorPosition: { top, left },
loaderItems: getNumOfMenuOptionsForItem(parseSandBoxItemToDetailedItem(item))
})
);
};
const loadPage = (pageNumber) => {
const newOffset = pageNumber * state.limit;
setState({ items: null, loading: true, error: null });
fetchPublishingHistoryPackageItems(site, packageId, { limit: state.limit, offset: newOffset }).subscribe({
next: (items) => {
setState({ items, loading: false, offset: newOffset, total: items.total });
},
error({ response }) {
setState({ error: response.response, loading: false });
}
});
};
function onRowsPerPageChange(rowsPerPage) {
setState({
limit: rowsPerPage,
offset: 0
});
}
return React.createElement(
EnhancedDialog,
{
fullWidth: true,
maxWidth: 'md',
...enhancedDialogProps,
title: React.createElement(FormattedMessage, {
id: 'packageDetailsDialog.packageDetailsDialogTitle',
defaultMessage: 'Publishing Package Details'
})
},
React.createElement(
DialogContent,
null,
state.loading &&
React.createElement(LoadingState, { styles: { root: { width: 100, height: dialogContentHeight } } }),
state.error && React.createElement(ApiResponseErrorState, { error: state.error }),
!Boolean(packageId) &&
React.createElement(
Typography,
{ color: 'error.main' },
React.createElement(FormattedMessage, {
id: 'packageDetailsDialog.missingPackageId',
defaultMessage: 'Unable to fetch package details as package id was not provided to this UI'
})
),
state.items &&
(state.items.length === 0
? React.createElement(EmptyState, {
title: React.createElement(FormattedMessage, {
id: 'packageDetailsDialog.emptyPackageMessage',
defaultMessage: 'The package is empty'
}),
subtitle: React.createElement(FormattedMessage, {
id: 'packageDetailsDialog.emptyPackageMessageSubtitle',
defaultMessage: 'Fetched package id is {packageId}',
values: { packageId }
})
})
: React.createElement(
React.Fragment,
null,
React.createElement(
List,
{ sx: { height: dialogContentHeight, overflowY: 'auto' } },
state.items.map((item) =>
React.createElement(
ListItemButton,
{
key: item.id,
onMouseOver: () => setOver(item.path),
onMouseOut: () => setOver(null),
sx: {
cursor: 'default',
justifyContent: 'space-between'
}
},
React.createElement(ItemDisplay, {
item: item,
titleDisplayProp: 'path',
showNavigableAsLinks: false
}),
over === item.path &&
React.createElement(
Tooltip,
{ title: React.createElement(FormattedMessage, { defaultMessage: 'Options' }) },
React.createElement(
IconButton,
{
size: 'small',
onClick: (e) => {
onOpenMenu(e.currentTarget, item);
},
sx: { padding: 0 }
},
React.createElement(MoreVertRoundedIcon, null)
)
)
)
)
)
))
),
React.createElement(
DialogFooter,
null,
React.createElement(
Box,
{ display: 'flex', justifyContent: 'space-between' },
React.createElement(Pager, {
totalPages: totalPages,
totalItems: state.total,
currentPage: currentPage,
rowsPerPage: state.limit,
onPagePickerChange: (page) => loadPage(page),
onPageChange: (page) => loadPage(page),
onRowsPerPageChange: onRowsPerPageChange
})
)
)
);
}
export default PackageDetailsDialog;