diff --git a/README.md b/README.md index 27af504..28ebdab 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,26 @@ Each level requires more work to integrate but makes editing easier. As the GSoC projects progresses more of these levels will be enabled so you can try them out. see [Hydra GSoC project progresses](https://github.com/orgs/collective/projects/3/views/4) +## Managing multiple frontends + +To switch to a different frontend in the Volto Hydra AdminUI, follow these steps: + +1. **Navigate to Personal Tools**: + - In the bottom of the toolbar on the left, click on "Personal Tools". + +2. **Go to Preferences**: + - From the Personal Tools menu, select "Preferences". + +3. **Change Frontend URL**: + - In the Preferences section, you will find an option to select the Frontend URL. + - You can either select a frontend URL from the available options or type in a custom URL: + - To select a URL from the options, simply choose from the dropdown menu. + - To enter a custom URL, click on the toggle to make the input field appear and type in your desired URL. + +This allows you to switch seamlessly between different frontend URLs for testing or editing purposes. + +**Note**: Make sure the frontend URL is correct and accessible to avoid any CORS issues. + ### Level 1: Show changes after save This is the most basic form of integration. diff --git a/packages/volto-hydra/src/actions.js b/packages/volto-hydra/src/actions.js index 4360841..2f39910 100644 --- a/packages/volto-hydra/src/actions.js +++ b/packages/volto-hydra/src/actions.js @@ -1,8 +1,8 @@ -import { SET_SELECTED_BLOCK } from './constants'; +import { SET_FRONTEND_PREVIEW_URL } from './constants'; -export function setSelectedBlock(uid) { +export function setFrontendPreviewUrl(url) { return { - type: SET_SELECTED_BLOCK, - uid: uid, + type: SET_FRONTEND_PREVIEW_URL, + url: url, }; } diff --git a/packages/volto-hydra/src/components/Iframe/View.jsx b/packages/volto-hydra/src/components/Iframe/View.jsx index 8470aa1..46fc446 100644 --- a/packages/volto-hydra/src/components/Iframe/View.jsx +++ b/packages/volto-hydra/src/components/Iframe/View.jsx @@ -12,20 +12,19 @@ import { import './styles.css'; import { useIntl } from 'react-intl'; import config from '@plone/volto/registry'; -import usePresetUrls from '../../utils/usePreseturls'; import isValidUrl from '../../utils/isValidUrl'; import { BlockChooser } from '@plone/volto/components'; import { createPortal } from 'react-dom'; import { usePopper } from 'react-popper'; -import UrlInput from '../UrlInput'; -import { useDispatch } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; +import { getURlsFromEnv } from '../../utils/getSavedURLs'; import { setSidebarTab } from '@plone/volto/actions'; /** - * Format the URL for the Iframe with location, token and enabling edit mode - * @param {*} url - * @param {*} token - * @returns {string} URL with the admin params + * Format the URL for the Iframe with location, token and edit mode + * @param {URL} url + * @param {String} token + * @returns {URL} URL with the admin params */ const getUrlWithAdminParams = (url, token) => { return typeof window !== 'undefined' @@ -51,10 +50,7 @@ const Iframe = (props) => { type: contentType, selectedBlock, } = props; - // const [ready, setReady] = useState(false); - // useEffect(() => { - // setReady(true); - // }, []); + const dispatch = useDispatch(); const [addNewBlockOpened, setAddNewBlockOpened] = useState(false); const [popperElement, setPopperElement] = useState(null); @@ -67,7 +63,7 @@ const Iframe = (props) => { { name: 'offset', options: { - offset: [0, -250], + offset: [0, -350], }, }, { @@ -88,16 +84,18 @@ const Iframe = (props) => { }, [selectedBlock]); //------------------------- - const [url, setUrl] = useState(''); - const [src, setSrc] = useState(''); - const history = useHistory(); + const [iframeSrc, setIframeSrc] = useState(null); + const urlFromEnv = getURlsFromEnv(); + const u = + useSelector((state) => state.frontendPreviewUrl.url) || + Cookies.get('iframe_url') || + urlFromEnv[0]; - const presetUrls = usePresetUrls(); - const defaultUrl = presetUrls[0]; - const savedUrl = Cookies.get('iframe_url'); - const initialUrl = savedUrl - ? getUrlWithAdminParams(savedUrl, token) - : getUrlWithAdminParams(defaultUrl, token); + useEffect(() => { + setIframeSrc(getUrlWithAdminParams(u, token)); + u && Cookies.set('iframe_url', u, { expires: 7 }); + }, [token, u]); + const history = useHistory(); //-----Experimental----- const intl = useIntl(); @@ -132,26 +130,19 @@ const Iframe = (props) => { const handleNavigateToUrl = useCallback( (givenUrl = null) => { - if (!isValidUrl(givenUrl) && !isValidUrl(url)) { + if (!isValidUrl(givenUrl)) { return; } // Update adminUI URL with the new URL - const formattedUrl = givenUrl ? new URL(givenUrl) : new URL(url); + const formattedUrl = new URL(givenUrl); const newOrigin = formattedUrl.origin; Cookies.set('iframe_url', newOrigin, { expires: 7 }); history.push(`${formattedUrl.pathname}`); }, - [history, url], + [history], ); - useEffect(() => { - setUrl( - `${savedUrl || defaultUrl}${window.location.pathname.replace('/edit', '')}`, - ); - setSrc(initialUrl); - }, [savedUrl, defaultUrl, initialUrl]); - useEffect(() => { //----------------Experimental---------------- const onDeleteBlock = (id, selectPrev) => { @@ -160,7 +151,7 @@ const Iframe = (props) => { onChangeFormData(newFormData); onSelectBlock(selectPrev ? previous : null); - const origin = new URL(src).origin; + const origin = new URL(iframeSrc).origin; document .getElementById('previewIframe') .contentWindow.postMessage( @@ -169,7 +160,7 @@ const Iframe = (props) => { ); }; //---------------------------------------------- - const initialUrlOrigin = initialUrl ? new URL(initialUrl).origin : ''; + const initialUrlOrigin = iframeSrc && new URL(iframeSrc).origin; const messageHandler = (event) => { if (event.origin !== initialUrlOrigin) { return; @@ -210,31 +201,28 @@ const Iframe = (props) => { window.removeEventListener('message', messageHandler); }; }, [ + dispatch, handleNavigateToUrl, history.location.pathname, - initialUrl, + iframeSrc, onChangeFormData, onSelectBlock, properties, - src, token, ]); useEffect(() => { - if (form && Object.keys(form).length > 0 && isValidUrl(src)) { + if (form && Object.keys(form).length > 0 && isValidUrl(iframeSrc)) { // Send the form data to the iframe - const origin = new URL(src).origin; + const origin = new URL(iframeSrc).origin; document .getElementById('previewIframe') .contentWindow.postMessage({ type: 'FORM_DATA', data: form }, origin); } - }, [form, initialUrl, src]); + }, [form, iframeSrc]); return (
-
- -
{addNewBlockOpened && createPortal(
{ ? (id, value) => { setAddNewBlockOpened(false); const newId = onInsertBlock(id, value); - const origin = new URL(src).origin; + const origin = new URL(iframeSrc).origin; document .getElementById('previewIframe') .contentWindow.postMessage( @@ -284,7 +272,7 @@ const Iframe = (props) => {