UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

162 lines (160 loc) 6.12 kB
/* * 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 } from 'react'; import { defineMessages, FormattedMessage } from 'react-intl'; import { initToolsPanelConfig, updateToolsPanelWidth } from '../../state/actions/preview'; import { useDispatch } from 'react-redux'; import ResizeableDrawer from '../ResizeableDrawer/ResizeableDrawer'; import { renderWidgets } from '../Widget'; import { SuspenseWithEmptyState } from '../Suspencified/Suspencified'; import { makeStyles } from 'tss-react/mui'; import { useSelection } from '../../hooks/useSelection'; import { useActiveSiteId } from '../../hooks/useActiveSiteId'; import { usePreviewState } from '../../hooks/usePreviewState'; import { useActiveUser } from '../../hooks/useActiveUser'; import { useLogicResource } from '../../hooks/useLogicResource'; import { useSiteUIConfig } from '../../hooks/useSiteUIConfig'; import { nnou } from '../../utils/object'; import { getStoredPreviewToolsPanelPage, getStoredPreviewToolsPanelWidth, setStoredPreviewToolsPanelWidth } from '../../utils/state'; import { useActiveSite } from '../../hooks/useActiveSite'; defineMessages({ previewSiteExplorerPanelTitle: { id: 'previewSiteExplorerPanel.title', defaultMessage: 'Project Explorer' } }); const useStyles = makeStyles()((theme) => ({ emptyState: { margin: `${theme.spacing(4)} ${theme.spacing(1)}` }, emptyStateImage: { width: '50%', marginBottom: theme.spacing(1) }, loadingViewRoot: { flex: 1, flexDirection: 'row' }, drawerBody: { paddingBottom: 50 } })); export function ToolsPanel() { const dispatch = useDispatch(); const { id: siteId, uuid } = useActiveSite(); const { classes } = useStyles(); const { showToolsPanel, toolsPanel } = usePreviewState(); const toolsPanelWidth = useSelection((state) => state.preview.toolsPanelWidth); const pages = useSelection((state) => state.preview.toolsPanelPageStack); const uiConfig = useSiteUIConfig(); const baseUrl = useSelection((state) => state.env.authoringBase); const { username } = useActiveUser(); useEffect(() => { if (nnou(uiConfig.xml) && !toolsPanel) { const storedPage = getStoredPreviewToolsPanelPage(uuid, username); const toolsPanelWidth = getStoredPreviewToolsPanelWidth(siteId, username); dispatch(initToolsPanelConfig({ configXml: uiConfig.xml, storedPage, toolsPanelWidth })); } }, [uiConfig.xml, toolsPanel, dispatch, uuid, username, siteId]); const resource = useLogicResource(toolsPanel, { errorSelector: (source) => uiConfig.error, resultSelector: (source) => source.widgets, shouldReject: (source) => false, shouldResolve: (source) => Boolean(source), shouldRenew: (source, resource) => uiConfig.isFetching || resource.complete }); const onWidthChange = (width) => { setStoredPreviewToolsPanelWidth(siteId, username, width); dispatch( updateToolsPanelWidth({ width }) ); }; return React.createElement( ResizeableDrawer, { belowToolbar: true, open: showToolsPanel, width: toolsPanelWidth, classes: { drawerBody: classes.drawerBody }, onWidthChange: onWidthChange }, React.createElement( SuspenseWithEmptyState, { resource: resource, loadingStateProps: { classes: { root: classes.loadingViewRoot } }, withEmptyStateProps: { isEmpty: (widgets) => !siteId || (widgets === null || widgets === void 0 ? void 0 : widgets.length) === 0, emptyStateProps: Object.assign( Object.assign( { title: siteId ? React.createElement(FormattedMessage, { id: 'previewTools.noWidgetsMessage', defaultMessage: 'No tools have been configured' }) : React.createElement(FormattedMessage, { id: 'previewTools.choseSiteMessage', defaultMessage: 'Please choose project' }) }, !siteId && { image: `${baseUrl}/static-assets/images/choose_option.svg` } ), { classes: { root: classes.emptyState, image: classes.emptyStateImage } } ) } }, React.createElement(ToolsPaneBody, { resource: resource, pageStack: pages }) ) ); } function ToolsPaneBody(props) { const root = props.resource.read(); const site = useActiveSiteId(); const { pageStack } = props; const { rolesBySite } = useActiveUser(); return React.createElement( React.Fragment, null, renderWidgets(pageStack.length ? pageStack.slice(props.pageStack.length - 1) : root, { userRoles: rolesBySite[site] }) ); } export default ToolsPanel;