Skip to content
Merged
75 changes: 66 additions & 9 deletions resources/js/pages/utilities/Cache.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<script setup>
import { router } from '@inertiajs/vue3';
import Head from '@/pages/layout/Head.vue';
import { Header, Button, Panel, PanelHeader, Heading, Card, Description, Badge, DocsCallout, CommandPaletteItem } from '@ui';
import {
Header, Button, Panel, PanelHeader, Heading, Card, Description, Badge, DocsCallout, CommandPaletteItem,
Dropdown, DropdownMenu, DropdownItem, Textarea, ErrorMessage, Modal, ModalClose
} from '@ui';
import { ref } from 'vue';

const props = defineProps([
'stache',
Expand All @@ -12,6 +16,7 @@ const props = defineProps([
'clearStacheUrl',
'warmStacheUrl',
'clearStaticUrl',
'invalidatePagesUrl',
'clearApplicationUrl',
'clearImageUrl',
]);
Expand Down Expand Up @@ -39,6 +44,31 @@ function clearApplication() {
function clearImage() {
router.post(props.clearImageUrl);
}

const staticUrls = ref(null);
const invalidateStaticUrlsModal = ref(false);
const isInvalidatingStaticUrls = ref(false);
const invalidateStaticUrlsError = ref(null);

function invalidateStaticUrls() {
isInvalidatingStaticUrls.value = true;
invalidateStaticUrlsError.value = null;

router.post(
props.invalidatePagesUrl, // todo: rename this to match the method?
{
urls: staticUrls.value?.split('\n'),
},
{
onSuccess: () => {
staticUrls.value = null;
invalidateStaticUrlsModal.value = false;
},
onError: (errors) => invalidateStaticUrlsError.value = errors.urls,
onFinish: () => isInvalidatingStaticUrls.value = false,
},
);
}
</script>

<template>
Expand Down Expand Up @@ -102,14 +132,41 @@ function clearImage() {
<PanelHeader class="flex items-center justify-between min-h-10">
<Heading>{{ __('Static Page Cache') }}</Heading>
<div v-if="static.enabled" class="flex gap-2">
<CommandPaletteItem
category="Actions"
:text="[__('Clear'), __('Static Page Cache')]"
icon="live-preview"
:action="clearStatic"
>
<Button :text="__('Clear')" size="sm" @click="clearStatic" />
</CommandPaletteItem>
<CommandPaletteItem
category="Actions"
:text="[__('Clear'), __('Static Page Cache')]"
icon="live-preview"
:action="invalidateStaticUrls"
>
<Dropdown align="end">
<template #trigger>
<Button :text="__('Invalidate')" size="sm" icon-append="chevron-down" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Everything')" icon="layers-stacks" @click="clearStatic" />
<DropdownItem :text="__('Specific URLs')" icon="link" @click="invalidateStaticUrlsModal = true" />
</DropdownMenu>
</Dropdown>
</CommandPaletteItem>

<Modal :title="__('Invalidate Static Cache')" v-model:open="invalidateStaticUrlsModal">
<p>{{ __('Specify the URLs you want to invalidate. One line per URL.') }}</p>
<Textarea class="font-mono" v-model="staticUrls" :disabled="isInvalidatingStaticUrls" />
<ErrorMessage v-if="invalidateStaticUrlsError" :text="invalidateStaticUrlsError" class="mt-2" />

<div class="flex items-center justify-end space-x-3 pt-3 pb-1">
<ModalClose asChild>
<Button variant="ghost" :disabled="isInvalidatingStaticUrls" :text="__('Cancel')" />
</ModalClose>
<Button
type="submit"
variant="primary"
:disabled="isInvalidatingStaticUrls"
:text="__('Invalidate URLs')"
@click="invalidateStaticUrls"
/>
</div>
</Modal>
</div>
</PanelHeader>
<Card class="flex-1">
Expand Down
9 changes: 7 additions & 2 deletions src/CP/Utilities/CoreUtilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ public static function boot()
->description(__('statamic::messages.cache_utility_description'))
->docsUrl(Statamic::docsUrl('utilities/cache-manager'))
->routes(function ($router) {
$router->post('cache/{cache}', [CacheController::class, 'clear'])->name('clear');
$router->post('cache/{cache}/warm', [CacheController::class, 'warm'])->name('warm');
$router->post('clear-all', [CacheController::class, 'clearAll'])->name('clear-all');
$router->post('clear-stache', [CacheController::class, 'clearStacheCache'])->name('clear-stache');
$router->post('warm-stache', [CacheController::class, 'warmStacheCache'])->name('warm-stache');
$router->post('clear-static', [CacheController::class, 'clearStaticCache'])->name('clear-static');
$router->post('invalidate-static-pages', [CacheController::class, 'invalidateStaticUrls'])->name('invalidate-static-pages');
$router->post('clear-application-cache', [CacheController::class, 'clearApplicationCache'])->name('clear-application-cache');
$router->post('clear-image-cache', [CacheController::class, 'clearImageCache'])->name('clear-image-cache');
});

Utility::register('phpinfo')
Expand Down
67 changes: 41 additions & 26 deletions src/Http/Controllers/CP/Utilities/CacheController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
use Illuminate\Support\Facades\Artisan;
use Inertia\Inertia;
use League\Glide\Server;
use Statamic\Facades\Site;
use Statamic\Facades\Stache;
use Statamic\Facades\StaticCache;
use Statamic\Facades\URL;
use Statamic\Http\Controllers\CP\CpController;
use Statamic\StaticCaching\Cacher;
use Statamic\Support\Str;

class CacheController extends CpController
Expand All @@ -20,12 +23,13 @@ public function index()
'cache' => $this->getApplicationCacheStats(),
'static' => $this->getStaticCacheStats(),
'images' => $this->getImageCacheStats(),
'clearAllUrl' => cp_route('utilities.cache.clear', 'all'),
'clearStacheUrl' => cp_route('utilities.cache.clear', 'stache'),
'warmStacheUrl' => cp_route('utilities.cache.warm', 'stache'),
'clearStaticUrl' => cp_route('utilities.cache.clear', 'static'),
'clearApplicationUrl' => cp_route('utilities.cache.clear', 'application'),
'clearImageUrl' => cp_route('utilities.cache.clear', 'image'),
'clearAllUrl' => cp_route('utilities.cache.clear-all'),
'clearStacheUrl' => cp_route('utilities.cache.clear-stache'),
'warmStacheUrl' => cp_route('utilities.cache.warm-stache'),
'clearStaticUrl' => cp_route('utilities.cache.clear-static'),
'invalidatePagesUrl' => cp_route('utilities.cache.invalidate-static-pages'),
'clearApplicationUrl' => cp_route('utilities.cache.clear-application-cache'),
'clearImageUrl' => cp_route('utilities.cache.clear-image-cache'),
]);
}

Expand Down Expand Up @@ -77,14 +81,7 @@ protected function getStaticCacheStats()
];
}

public function clear(Request $request, $cache)
{
$method = 'clear'.ucfirst($cache).'Cache';

return $this->$method();
}

protected function clearAllCache()
public function clearAll(Request $request)
{
$this->clearStacheCache();
$this->clearStaticCache();
Expand All @@ -94,21 +91,46 @@ protected function clearAllCache()
return back()->withSuccess(__('All caches cleared.'));
}

protected function clearStacheCache()
public function clearStacheCache()
{
Stache::refresh();

return back()->withSuccess(__('Stache cleared.'));
}

protected function clearStaticCache()
public function clearStaticCache()
{
StaticCache::flush();

return back()->withSuccess(__('Static page cache cleared.'));
}

protected function clearApplicationCache()
public function invalidateStaticUrls(Request $request)
{
$request->validate([
'urls' => ['required', 'array'],
]);

$urls = $request->collect('urls');

$absoluteUrls = $urls->filter(fn (string $rule) => URL::isAbsolute($rule))->all();

$prefixedRelativeUrls = $urls
->reject(fn (string $rule) => URL::isAbsolute($rule))
->map(fn (string $rule) => URL::tidy(Site::selected()->url().'/'.$rule, withTrailingSlash: false))
->all();

$urls = [
...$absoluteUrls,
...$prefixedRelativeUrls,
];

app(Cacher::class)->invalidateUrls($urls);

return back()->withSuccess(__('Invalidated URLs in the Static Cache.'));
}

public function clearApplicationCache()
{
Artisan::call('cache:clear');

Expand All @@ -118,21 +140,14 @@ protected function clearApplicationCache()
return back()->withSuccess(__('Application cache cleared.'));
}

protected function clearImageCache()
public function clearImageCache()
{
Artisan::call('statamic:glide:clear');

return back()->withSuccess(__('Image cache cleared.'));
}

public function warm(Request $request, $cache)
{
$method = 'warm'.ucfirst($cache).'Cache';

return $this->$method();
}

protected function warmStacheCache()
public function warmStacheCache()
{
Stache::warm();

Expand Down