View file File name : index.js Content :import { Button, Container, Modal, Page } from '@newfold/ui-component-library'; import { XMarkIcon, CheckIcon } from '@heroicons/react/24/outline'; import { default as StagingSite } from '../stagingSite/'; import { default as ProductionSite } from '../productionSite/'; import { default as defaultText } from './defaultText'; /** * Staging Module * For use in brand plugin apps to display staging page * * @param {*} props * @returns */ const Staging = ({methods, constants, ...props}) => { const apiNamespace = '/newfold-staging/v1/'; const [ isLoading, setIsLoading ] = methods.useState( true ); const [ isThinking, setIsThinking ] = methods.useState( false ); const [ isError, setIsError ] = methods.useState( false ); const [ hasStaging, setHasStaging ] = methods.useState( null ); const [ isProduction, setIsProduction ] = methods.useState( true ); const [ creationDate, setCreationDate ] = methods.useState( null ); const [ productionDir, setProductionDir ] = methods.useState( null ); const [ productionUrl, setProductionUrl ] = methods.useState( null ); const [ stagingDir, setStagingDir ] = methods.useState( null ); const [ stagingUrl, setStagingUrl ] = methods.useState( null ); const [ modalChildren, setModalChildren ] = methods.useState( <div /> ); const [ modalOpen, setModalOpen ] = methods.useState( false ); let notify = methods.useNotification(); // set defaults if not provided constants.text = Object.assign(defaultText, constants.text); // Setup values from response const setup = ( response ) => { if ( response.hasOwnProperty( 'stagingExists' ) ) { setHasStaging( response.stagingExists ); } if ( response.hasOwnProperty( 'currentEnvironment' ) ) { setIsProduction( response.currentEnvironment === 'production' ); } if ( response.hasOwnProperty( 'productionDir' ) ) { setProductionDir( response.productionDir ); } if ( response.hasOwnProperty( 'productionUrl' ) ) { setProductionUrl( response.productionUrl ); } if ( response.hasOwnProperty( 'stagingDir' ) ) { setStagingDir( response.stagingDir ); } if ( response.hasOwnProperty( 'stagingUrl' ) ) { setStagingUrl( response.stagingUrl ); } if ( response.hasOwnProperty( 'creationDate' ) ) { setCreationDate( response.creationDate ); } }; const setError = ( error ) => { // console.log('setError', error); setIsLoading( false ); setIsThinking( false ); setIsError(true); makeNotice( 'error', constants.text.error, error, 'error' ); }; const catchError = (error) => { if ( error.hasOwnProperty( 'message' ) ) { setError(error.message); } else if ( error.hasOwnProperty( 'code' ) ) { setError(error.code); } else if ( error.hasOwnProperty( 'status' ) ) { setError(error.status); } else if ( error.hasOwnProperty( 'data' ) && error.data.hasOwnProperty('status') ) { setError(error.data.status); } else { setError(constants.text.unknownErrorMessage); } }; const makeNotice = (id, title, description, variant="success", duration=false) => { notify.push(`staging-notice-${id}`, { title, description: ( <span> {description} </span> ), variant, autoDismiss: duration, }); }; /** * on mount load staging data from module api */ methods.useEffect(() => { init(); }, [] ); const init = () => { // console.log('Init - Loading Staging Data'); setIsError(false); setIsLoading(true); stagingApiFetch( 'staging', null, 'GET', (response) => { // console.log('Init Staging Data:', response); // validate response data if ( response.hasOwnProperty('currentEnvironment') ) { //setup with fresh data setup( response ); } else if ( response.hasOwnProperty('code') && response.code === 'error_response' ) { setError( response.message ); // report known error } else { setError( unknownErrorMsg ); // report unknown error } setIsThinking( false ); setIsLoading( false ); } ); } const createStaging = () => { // console.log('create staging'); makeNotice( 'creating', constants.text.working, constants.text.createNoticeStartText, 'info', 8000 ); // setIsCreatingStaging(true); stagingApiFetch( 'staging', null, 'POST', (response) => { // console.log('Create Staging Callback', response); if ( response.hasOwnProperty('status') ) { if ( response.status === 'success' ){ //setup with fresh data setup( response ); makeNotice( 'created', constants.text.createNoticeCompleteText, response.message ); } else { setError( response.message ); // report known error } } else { setError( unknownErrorMsg ); // report unknown error } setIsThinking( false ); // setIsCreatingStaging(false); } ); }; const deleteStaging = () => { // console.log('delete staging'); makeNotice( 'deleting', constants.text.working, constants.text.deleteNoticeStartText, 'info', 8000 ); stagingApiFetch( 'staging', null, 'DELETE', (response) => { // console.log('Delete staging callback', response); // validate response data if ( response.hasOwnProperty('status') ) { if ( response.status === 'success' ){ // setup with fresh data setHasStaging( false ); makeNotice( 'deleted', constants.text.deleteNoticeCompleteText, response.message ); } else { setError( response.message ); } } else { setError( unknownErrorMsg ); // report unknown error } setIsThinking( false ); } ); }; const clone = () => { // console.log('clone production to staging'); makeNotice( 'cloning', constants.text.working, constants.text.cloneNoticeStartText, 'info', 8000 ); stagingApiFetch( 'staging/clone', null, 'POST', (response) => { // console.log('Clone Callback', response); // validate response data if ( response.hasOwnProperty('status') ) { // setup with fresh data if ( response.status === 'success' ){ setHasStaging( true ); makeNotice( 'cloned', constants.text.cloneNoticeCompleteText, response.message ); } else { setError( response.message ); } } else { setError( unknownErrorMsg ); // report unknown error } setIsThinking( false ); } ); }; const switchToStaging = () => { if ( !isProduction ) { // console.log('Already on staging.'); } else { setModal( constants.text.switchToStaging, constants.text.switchToStagingDescription, switchToEnv, 'staging', constants.text.switch ); } }; const switchToProduction = () => { if ( isProduction ) { // console.log('Already on production.'); } else { setModal( constants.text.switchToProduction, constants.text.switchToProductionDescription, switchToEnv, 'production', constants.text.switch ); } }; /** * * @param {string} env One of 'staging' or 'production' */ const switchToEnv = ( env ) => { // console.log('switching to', env, `/switch-to?env=${ env }`); // setSwitchingTo( env ); setIsThinking( true ); if ( env === 'production' ) { makeNotice( 'switching', constants.text.working, constants.text.switchToProductionNoticeStartText, 'info', 8000 ); } else { makeNotice( 'switching', constants.text.working, constants.text.switchToStagingNoticeStartText, 'info', 8000 ); } stagingApiFetch( 'staging/switch-to', {'env': env}, 'GET', (response) => { // console.log('Switch Callback', response); // validate response data if ( response.hasOwnProperty( 'load_page' ) ) { window.location.href = response.load_page; // navigate(response.load_page); makeNotice( 'redirecting', constants.text.switching, constants.text.switchToProductionNoticeCompleteText, 'success', 8000 ); } else if ( response.hasOwnProperty('status') && response.status === 'error' ) { setError(response.message); } else { setError( unknownErrorMsg ); // report unknown error } } ); }; /** * * @param {string} type One of 'all', 'files', or 'db' */ const deployStaging = ( type ) => { // console.log('Deploy', type); makeNotice( 'deploying', constants.text.working, constants.text.deployNoticeStartText, 'info', 8000 ); stagingApiFetch( 'staging/deploy', {'type': type}, 'POST', (response) => { // console.log('Deploy Callback', response); // validate response data if ( response.hasOwnProperty('status') ) { // setup with fresh data if ( response.status === 'success' ){ makeNotice( 'deployed', constants.text.deployNoticeCompleteText, response.message ); } else { setError( response.message ); } } else { setError( unknownErrorMsg ); // report unknown error } setIsThinking( false ); } ); }; /** * Wrapper method to interface with staging endpoints * * @param path append to the end of the apiNamespace * @param method GET or POST, default GET * @param thenCallback method to call in promise then * @param passError setter for the error in component * @return apiFetch promise */ const stagingApiFetch = ( path = '', qs = {}, method = 'GET', thenCallback, errorCallback = catchError ) => { setIsThinking( true ); return methods.apiFetch({ url: methods.NewfoldRuntime.createApiUrl( apiNamespace + path, qs), method, }).then( (response) => { thenCallback( response ); }).catch( (error) => { errorCallback( error ); }) }; const modalClose = () => { setModalOpen(false); } const setModal = (title, description, callback, callbackParams=null, ctaText=constants.text.proceed) => { setModalChildren( <Modal.Panel> <Modal.Title className="nfd-text-2xl nfd-font-medium nfd-text-title">{title}</Modal.Title> <Modal.Description className="nfd-mt-8 nfd-mb-8">{description}</Modal.Description> <div className="nfd-flex nfd-justify-between nfd-items-center nfd-flex-wrap nfd-gap-3"> <Button variant="error" onClick={ () => { setModalOpen(false); }} > <XMarkIcon /> {constants.text.cancel} </Button> <Button variant="primary" onClick={ () => { setModalOpen(false); callback(callbackParams); }} > <CheckIcon /> {ctaText} </Button> </div> </Modal.Panel> ); setModalOpen(true); }; const getClasses = () => { let theclasses = ''; if ( isLoading ) { theclasses = 'is-loading'; } else if ( isThinking ) { theclasses = 'is-thinking'; } else if ( isError ) { theclasses = 'is-error'; } return theclasses; }; return ( <Page title={constants.text.title} className={methods.classnames('newfold-staging-page', getClasses())}> <Container className={'wppbh-app-staging-container'}> <div className={methods.classnames('newfold-staging-wrapper')}> <Container.Header title={constants.text.title} description={constants.text.subTitle} className={'newfold-staging-header'} /> <Container.Block separator={true} className={'newfold-staging-prod'}> <ProductionSite methods={methods} constants={constants} isProduction={isProduction} hasStaging={hasStaging} productionUrl={productionUrl} cloneMe={clone} switchToMe={switchToProduction} setModal={setModal} /> </Container.Block> <Container.Block className={'newfold-staging-staging'}> <StagingSite methods={methods} constants={constants} isProduction={isProduction} hasStaging={hasStaging} setHasStaging={setHasStaging} createMe={createStaging} deleteMe={deleteStaging} deployMe={deployStaging} switchToMe={switchToStaging} stagingUrl={stagingUrl} creationDate={creationDate} setModal={setModal} /> </Container.Block> <Modal isOpen={ modalOpen } onClose={ modalClose } children={ modalChildren } /> </div> </Container> </Page> ); }; export default Staging;