-
Notifications
You must be signed in to change notification settings - Fork 2k
Dashboard v2: Implement Settings -> Caching #103826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
import { DataForm } from '@automattic/dataviews'; | ||
import { useQuery, useMutation } from '@tanstack/react-query'; | ||
import { | ||
Card, | ||
CardBody, | ||
__experimentalHStack as HStack, | ||
__experimentalVStack as VStack, | ||
Button, | ||
} from '@wordpress/components'; | ||
import { useDispatch } from '@wordpress/data'; | ||
import { createInterpolateElement } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { store as noticesStore } from '@wordpress/notices'; | ||
import { useEffect, useState } from 'react'; | ||
import { | ||
siteQuery, | ||
siteEdgeCacheStatusQuery, | ||
siteEdgeCacheStatusMutation, | ||
siteEdgeCacheClearMutation, | ||
siteObjectCacheClearMutation, | ||
} from '../../app/queries'; | ||
import { ActionList } from '../../components/action-list'; | ||
import PageLayout from '../../components/page-layout'; | ||
import SettingsCallout from '../settings-callout'; | ||
import SettingsPageHeader from '../settings-page-header'; | ||
import type { Site } from '../../data/types'; | ||
import type { Field } from '@automattic/dataviews'; | ||
|
||
type CachingFormData = { | ||
active: boolean; | ||
}; | ||
|
||
const fields: Field< CachingFormData >[] = [ | ||
{ | ||
id: 'active', | ||
label: __( 'Enable global edge caching for faster content delivery' ), | ||
Edit: 'checkbox', | ||
}, | ||
]; | ||
|
||
const form = { | ||
type: 'regular' as const, | ||
fields: [ 'active' ], | ||
}; | ||
|
||
export function canUpdateCaching( site: Site ) { | ||
return site.is_wpcom_atomic; | ||
} | ||
|
||
export default function CachingSettings( { siteSlug }: { siteSlug: string } ) { | ||
const { data: site } = useQuery( siteQuery( siteSlug ) ); | ||
const canUpdate = site && canUpdateCaching( site ); | ||
|
||
const { data: isEdgeCacheActive } = useQuery( { | ||
...siteEdgeCacheStatusQuery( siteSlug ), | ||
enabled: canUpdate, | ||
} ); | ||
const edgeCacheStatusMutation = useMutation( siteEdgeCacheStatusMutation( siteSlug ) ); | ||
const edgeCacheClearMutation = useMutation( siteEdgeCacheClearMutation( siteSlug ) ); | ||
const objectCacheClearMutation = useMutation( siteObjectCacheClearMutation( siteSlug ) ); | ||
|
||
const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); | ||
|
||
const [ formData, setFormData ] = useState< CachingFormData >( { | ||
active: isEdgeCacheActive ?? false, | ||
} ); | ||
|
||
const isDirty = isEdgeCacheActive !== formData.active; | ||
const { isPending } = edgeCacheStatusMutation; | ||
|
||
const handleUpdateEdgeCacheStatus = ( e: React.FormEvent ) => { | ||
e.preventDefault(); | ||
edgeCacheStatusMutation.mutate( formData.active, { | ||
onSuccess: () => { | ||
createSuccessNotice( __( 'Settings saved.' ), { type: 'snackbar' } ); | ||
}, | ||
onError: () => { | ||
createErrorNotice( __( 'Failed to save settings.' ), { type: 'snackbar' } ); | ||
}, | ||
} ); | ||
}; | ||
|
||
const handleClearEdgeCache = () => { | ||
edgeCacheClearMutation.mutate( undefined, { | ||
onSuccess: () => { | ||
createSuccessNotice( __( 'Global edge cache cleared.' ), { type: 'snackbar' } ); | ||
}, | ||
onError: () => { | ||
createErrorNotice( __( 'Failed to clear edge cache.' ), { type: 'snackbar' } ); | ||
}, | ||
} ); | ||
}; | ||
|
||
const handleClearObjectCache = () => { | ||
objectCacheClearMutation.mutate( 'Manually clearing again.', { | ||
onSuccess: () => { | ||
createSuccessNotice( __( 'Object cache cleared.' ), { type: 'snackbar' } ); | ||
}, | ||
onError: () => { | ||
createErrorNotice( __( 'Failed to clear object cache.' ), { type: 'snackbar' } ); | ||
}, | ||
} ); | ||
}; | ||
|
||
const [ isClearingAllCaches, setIsClearingAllCaches ] = useState( false ); | ||
|
||
useEffect( () => { | ||
if ( ! edgeCacheClearMutation.isPending && ! objectCacheClearMutation.isPending ) { | ||
setIsClearingAllCaches( false ); | ||
} | ||
}, [ edgeCacheClearMutation.isPending, objectCacheClearMutation.isPending ] ); | ||
|
||
const handleClearAllCaches = () => { | ||
if ( isEdgeCacheActive ) { | ||
handleClearEdgeCache(); | ||
} | ||
handleClearObjectCache(); | ||
|
||
setIsClearingAllCaches( true ); | ||
}; | ||
|
||
const renderCallout = () => { | ||
return <SettingsCallout siteSlug={ siteSlug } />; | ||
}; | ||
|
||
const renderForm = () => { | ||
return ( | ||
<> | ||
<Card> | ||
<CardBody> | ||
<form onSubmit={ handleUpdateEdgeCacheStatus }> | ||
<VStack spacing={ 4 } style={ { padding: '8px 0' } }> | ||
<DataForm< CachingFormData > | ||
data={ formData } | ||
fields={ fields } | ||
form={ form } | ||
onChange={ ( edits: Partial< CachingFormData > ) => { | ||
setFormData( ( data ) => ( { ...data, ...edits } ) ); | ||
} } | ||
/> | ||
<HStack justify="flex-start"> | ||
<Button | ||
variant="primary" | ||
type="submit" | ||
isBusy={ isPending } | ||
disabled={ isPending || ! isDirty } | ||
> | ||
{ __( 'Save' ) } | ||
</Button> | ||
</HStack> | ||
</VStack> | ||
</form> | ||
</CardBody> | ||
</Card> | ||
|
||
<VStack spacing={ 4 }> | ||
<ActionList | ||
title={ __( 'Clear caches' ) } | ||
description={ __( | ||
'Clearing the cache may temporarily make your site less responsive.' | ||
) } | ||
> | ||
<ActionList.ActionItem | ||
title={ __( 'Global edge cache' ) } | ||
description={ __( 'Edge caching enables faster content delivery.' ) } | ||
actions={ | ||
<Button | ||
variant="secondary" | ||
size="compact" | ||
onClick={ handleClearEdgeCache } | ||
isBusy={ edgeCacheClearMutation.isPending && ! isClearingAllCaches } | ||
disabled={ | ||
! isEdgeCacheActive || edgeCacheClearMutation.isPending || isClearingAllCaches | ||
} | ||
> | ||
{ __( 'Clear' ) } | ||
</Button> | ||
} | ||
/> | ||
<ActionList.ActionItem | ||
title={ __( 'Object cache' ) } | ||
description={ __( 'Data is cached using Memcached to reduce database lookups.' ) } | ||
actions={ | ||
<Button | ||
variant="secondary" | ||
size="compact" | ||
onClick={ handleClearObjectCache } | ||
isBusy={ objectCacheClearMutation.isPending && ! isClearingAllCaches } | ||
disabled={ objectCacheClearMutation.isPending || isClearingAllCaches } | ||
> | ||
{ __( 'Clear' ) } | ||
</Button> | ||
} | ||
/> | ||
</ActionList> | ||
<ActionList> | ||
<ActionList.ActionItem | ||
title={ __( 'Clear all caches' ) } | ||
actions={ | ||
<Button | ||
variant="secondary" | ||
size="compact" | ||
onClick={ handleClearAllCaches } | ||
isBusy={ isClearingAllCaches } | ||
disabled={ isClearingAllCaches } | ||
> | ||
{ __( 'Clear all' ) } | ||
</Button> | ||
} | ||
/> | ||
</ActionList> | ||
</VStack> | ||
</> | ||
); | ||
}; | ||
|
||
const description = canUpdate | ||
? createInterpolateElement( | ||
__( 'Manage your site’s server-side caching. <learnMoreLink />.' ), | ||
{ | ||
learnMoreLink: <a href="#learn-more">{ __( 'Learn more' ) }</a>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this is waiting for the help center to land? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, we have this placeholder all over the place, we should clean this up when help center is ready. |
||
} | ||
) | ||
: ''; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The description in this upsell situation is not accurate when the site is Business but not Atomic-transferrred yet. I talked more this in DOTCOM-13376. Let's solve it separately |
||
|
||
return ( | ||
<PageLayout | ||
size="small" | ||
header={ <SettingsPageHeader title={ __( 'Caching' ) } description={ description } /> } | ||
> | ||
{ ! canUpdate ? renderCallout() : renderForm() } | ||
</PageLayout> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can now move this to https://github.com/Automattic/wp-calypso/blob/trunk/client/dashboard/utils/site-features.ts 😀