mirror of https://github.com/halo-dev/halo
refactor: remove page cache feature (#6108)
#### What type of PR is this? /area core /kind api-change /milestone 2.17.x #### What this PR does / why we need it: 移除内置的页面静态缓存功能,后续将由 https://github.com/halo-sigs/plugin-page-cache 插件提供。 #### Which issue(s) this PR fixes: Fixes #5639 #### Special notes for your reviewer: #### Does this PR introduce a user-facing change? ```release-note 移除内置的页面静态缓存功能,后续由 https://github.com/halo-sigs/plugin-page-cache 插件提供。 ```pull/6216/head
parent
4cafdb5a72
commit
f0445f4e51
|
@ -2366,31 +2366,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/caches/{name}": {
|
||||
"delete": {
|
||||
"description": "Evict a cache.",
|
||||
"operationId": "EvictCache",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Cache name",
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"CacheV1alpha1Console"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/comments": {
|
||||
"get": {
|
||||
"description": "List comments.",
|
||||
|
@ -19692,12 +19667,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -21592,12 +21567,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -233,31 +233,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/caches/{name}": {
|
||||
"delete": {
|
||||
"description": "Evict a cache.",
|
||||
"operationId": "EvictCache",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Cache name",
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"CacheV1alpha1Console"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/comments": {
|
||||
"get": {
|
||||
"description": "List comments.",
|
||||
|
@ -5166,12 +5141,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -5677,12 +5652,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10609,12 +10609,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -11799,12 +11799,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1582,12 +1582,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,5 +9,6 @@ package run.halo.app.theme.router;
|
|||
public enum ModelConst {
|
||||
;
|
||||
public static final String TEMPLATE_ID = "_templateId";
|
||||
public static final String POWERED_BY_HALO_TEMPLATE_ENGINE = "poweredByHaloTemplateEngine";
|
||||
public static final Integer DEFAULT_PAGE_SIZE = 10;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package run.halo.app.cache;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.enums.ParameterIn.PATH;
|
||||
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
||||
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
|
||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||
|
||||
import org.springdoc.core.fn.builders.apiresponse.Builder;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.core.extension.endpoint.CustomEndpoint;
|
||||
|
||||
@Component
|
||||
public class CacheEndpoint implements CustomEndpoint {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
public CacheEndpoint(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterFunction<ServerResponse> endpoint() {
|
||||
var tag = "CacheV1alpha1Console";
|
||||
return route()
|
||||
.DELETE("/caches/{name}", this::evictCache, builder -> builder
|
||||
.tag(tag)
|
||||
.operationId("EvictCache")
|
||||
.description("Evict a cache.")
|
||||
.parameter(parameterBuilder()
|
||||
.name("name")
|
||||
.in(PATH)
|
||||
.required(true)
|
||||
.description("Cache name"))
|
||||
.response(Builder.responseBuilder()
|
||||
.responseCode(String.valueOf(NO_CONTENT.value())))
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> evictCache(ServerRequest request) {
|
||||
var cacheName = request.pathVariable("name");
|
||||
if (cacheManager.getCacheNames().contains(cacheName)) {
|
||||
var cache = cacheManager.getCache(cacheName);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
}
|
||||
}
|
||||
return ServerResponse.accepted().build();
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package run.halo.app.cache;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
|
||||
/**
|
||||
* Cached response. Refer to
|
||||
* <a href="https://github.com/spring-cloud/spring-cloud-gateway/blob/f98aa6d47bf802019f07063f4fd7af6047f15116/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/CachedResponse.java">here</a> }
|
||||
*/
|
||||
public record CachedResponse(HttpStatusCode statusCode,
|
||||
HttpHeaders headers,
|
||||
List<ByteBuffer> body,
|
||||
Instant timestamp) {
|
||||
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
package run.halo.app.cache;
|
||||
|
||||
import static java.nio.ByteBuffer.allocateDirect;
|
||||
import static org.springframework.http.HttpHeaders.CACHE_CONTROL;
|
||||
import static run.halo.app.infra.AnonymousUserConst.isAnonymousUser;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Slf4j
|
||||
public class PageCacheWebFilter implements WebFilter, Ordered {
|
||||
|
||||
public static final String REQUEST_TO_CACHE = "RequestCacheWebFilterToCache";
|
||||
|
||||
public static final String CACHE_NAME = "page";
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
public PageCacheWebFilter(CacheManager cacheManager) {
|
||||
this.cache = cacheManager.getCache(CACHE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.map(Authentication::getName)
|
||||
.filter(name -> isAnonymousUser(name) && requestCacheable(exchange.getRequest()))
|
||||
.switchIfEmpty(Mono.defer(() -> chain.filter(exchange).then(Mono.empty())))
|
||||
.flatMap(name -> {
|
||||
var cacheKey = generateCacheKey(exchange.getRequest());
|
||||
var cachedResponse = cache.get(cacheKey, CachedResponse.class);
|
||||
if (cachedResponse != null) {
|
||||
// cache hit, then write the cached response
|
||||
return writeCachedResponse(exchange.getResponse(), cachedResponse);
|
||||
}
|
||||
// decorate the ServerHttpResponse to cache the response
|
||||
var decoratedExchange = exchange.mutate()
|
||||
.response(new CacheResponseDecorator(exchange, cacheKey))
|
||||
.build();
|
||||
return chain.filter(decoratedExchange);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean requestCacheable(ServerHttpRequest request) {
|
||||
return HttpMethod.GET.equals(request.getMethod())
|
||||
&& !hasRequestBody(request)
|
||||
&& enableCacheByCacheControl(request.getHeaders());
|
||||
}
|
||||
|
||||
private boolean enableCacheByCacheControl(HttpHeaders headers) {
|
||||
return headers.getOrEmpty(CACHE_CONTROL)
|
||||
.stream()
|
||||
.noneMatch(cacheControl ->
|
||||
"no-store".equals(cacheControl) || "private".equals(cacheControl));
|
||||
}
|
||||
|
||||
private boolean responseCacheable(ServerWebExchange exchange) {
|
||||
var response = exchange.getResponse();
|
||||
if (!MediaType.TEXT_HTML.equals(response.getHeaders().getContentType())) {
|
||||
return false;
|
||||
}
|
||||
var statusCode = response.getStatusCode();
|
||||
if (statusCode == null || !statusCode.isSameCodeAs(HttpStatus.OK)) {
|
||||
return false;
|
||||
}
|
||||
return exchange.getAttributeOrDefault(REQUEST_TO_CACHE, false);
|
||||
}
|
||||
|
||||
private static boolean hasRequestBody(ServerHttpRequest request) {
|
||||
return request.getHeaders().getContentLength() > 0;
|
||||
}
|
||||
|
||||
private String generateCacheKey(ServerHttpRequest request) {
|
||||
return request.getURI().toASCIIString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// The filter should be after org.springframework.security.web.server.WebFilterChainProxy
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
private Mono<Void> writeCachedResponse(ServerHttpResponse response,
|
||||
CachedResponse cachedResponse) {
|
||||
response.setStatusCode(cachedResponse.statusCode());
|
||||
response.getHeaders().clear();
|
||||
response.getHeaders().addAll(cachedResponse.headers());
|
||||
var body = Flux.fromIterable(cachedResponse.body())
|
||||
.map(byteBuffer -> response.bufferFactory().wrap(byteBuffer));
|
||||
return response.writeWith(body);
|
||||
}
|
||||
|
||||
class CacheResponseDecorator extends ServerHttpResponseDecorator {
|
||||
|
||||
private final ServerWebExchange exchange;
|
||||
|
||||
private final String cacheKey;
|
||||
|
||||
public CacheResponseDecorator(ServerWebExchange exchange, String cacheKey) {
|
||||
super(exchange.getResponse());
|
||||
this.exchange = exchange;
|
||||
this.cacheKey = cacheKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Mono<Void> writeWith(@NonNull Publisher<? extends DataBuffer> body) {
|
||||
if (responseCacheable(exchange)) {
|
||||
var response = getDelegate();
|
||||
body = Flux.from(body)
|
||||
.map(dataBuffer -> {
|
||||
var byteBuffer = allocateDirect(dataBuffer.readableByteCount());
|
||||
dataBuffer.toByteBuffer(byteBuffer);
|
||||
DataBufferUtils.release(dataBuffer);
|
||||
return byteBuffer.asReadOnlyBuffer();
|
||||
})
|
||||
.collectSortedList()
|
||||
.doOnSuccess(byteBuffers -> {
|
||||
var headers = new HttpHeaders();
|
||||
headers.addAll(response.getHeaders());
|
||||
var cachedResponse = new CachedResponse(response.getStatusCode(),
|
||||
headers,
|
||||
byteBuffers,
|
||||
Instant.now());
|
||||
cache.put(cacheKey, cachedResponse);
|
||||
})
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.map(byteBuffer -> response.bufferFactory().wrap(byteBuffer));
|
||||
}
|
||||
// write the response
|
||||
return super.writeWith(body);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package run.halo.app.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import run.halo.app.cache.PageCacheWebFilter;
|
||||
|
||||
@EnableCaching
|
||||
@Configuration
|
||||
public class CacheConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "halo.cache.page.disabled", havingValue = "false")
|
||||
WebFilter pageCacheWebFilter(CacheManager cacheManager) {
|
||||
return new PageCacheWebFilter(cacheManager);
|
||||
}
|
||||
}
|
|
@ -5,12 +5,14 @@ import com.fasterxml.jackson.databind.MapperFeature;
|
|||
import java.io.IOException;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import run.halo.app.infra.properties.HaloProperties;
|
||||
import run.halo.app.search.lucene.LuceneSearchEngine;
|
||||
|
||||
@EnableCaching
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAsync
|
||||
public class HaloConfiguration {
|
||||
|
|
|
@ -5,8 +5,6 @@ import jakarta.validation.constraints.NotNull;
|
|||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
@ -63,9 +61,6 @@ public class HaloProperties implements Validator {
|
|||
@Valid
|
||||
private final AttachmentProperties attachment = new AttachmentProperties();
|
||||
|
||||
@Valid
|
||||
private final Map<String, CacheProperties> caches = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return HaloProperties.class.isAssignableFrom(clazz);
|
||||
|
|
|
@ -15,8 +15,8 @@ import org.thymeleaf.spring6.view.reactive.ThymeleafReactiveView;
|
|||
import org.thymeleaf.spring6.view.reactive.ThymeleafReactiveViewResolver;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.cache.PageCacheWebFilter;
|
||||
import run.halo.app.theme.finders.FinderRegistry;
|
||||
import run.halo.app.theme.router.ModelConst;
|
||||
|
||||
@Component("thymeleafReactiveViewResolver")
|
||||
public class HaloViewResolver extends ThymeleafReactiveViewResolver {
|
||||
|
@ -53,7 +53,7 @@ public class HaloViewResolver extends ThymeleafReactiveViewResolver {
|
|||
return themeResolver.getTheme(exchange).flatMap(theme -> {
|
||||
// calculate the engine before rendering
|
||||
setTemplateEngine(engineManager.getTemplateEngine(theme));
|
||||
exchange.getAttributes().put(PageCacheWebFilter.REQUEST_TO_CACHE, true);
|
||||
exchange.getAttributes().put(ModelConst.POWERED_BY_HALO_TEMPLATE_ENGINE, true);
|
||||
return super.render(model, contentType, exchange);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,10 +33,6 @@ spring:
|
|||
spec: expireAfterAccess=1h, maximumSize=10000
|
||||
|
||||
halo:
|
||||
caches:
|
||||
page:
|
||||
# Disable page cache by default due to experimental feature
|
||||
disabled: true
|
||||
work-dir: ${user.home}/.halo2
|
||||
plugin:
|
||||
plugins-root: ${halo.work-dir}/plugins
|
||||
|
|
|
@ -2,6 +2,7 @@ apiVersion: v1alpha1
|
|||
kind: "Role"
|
||||
metadata:
|
||||
name: role-template-manage-cache
|
||||
deletionTimestamp: 2024-06-01T00:00:00Z
|
||||
labels:
|
||||
halo.run/role-template: "true"
|
||||
annotations:
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
IconAccountCircleLine,
|
||||
IconArrowRight,
|
||||
IconBookRead,
|
||||
IconDatabase2Line,
|
||||
IconFolder,
|
||||
IconPages,
|
||||
IconPalette,
|
||||
|
@ -154,33 +153,6 @@ const actions: Action[] = [
|
|||
},
|
||||
permissions: ["system:posts:manage"],
|
||||
},
|
||||
{
|
||||
icon: markRaw(IconDatabase2Line),
|
||||
title: t(
|
||||
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.title"
|
||||
),
|
||||
action: () => {
|
||||
Dialog.warning({
|
||||
title: t(
|
||||
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.dialog_title"
|
||||
),
|
||||
description: t(
|
||||
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.dialog_content"
|
||||
),
|
||||
confirmText: t("core.common.buttons.confirm"),
|
||||
cancelText: t("core.common.buttons.cancel"),
|
||||
onConfirm: async () => {
|
||||
await consoleApiClient.cache.evictCache({ name: "page" });
|
||||
Toast.success(
|
||||
t(
|
||||
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.success_message"
|
||||
)
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
permissions: ["system:caches:manage"],
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
AuthProviderV1alpha1Api,
|
||||
AuthProviderV1alpha1ConsoleApi,
|
||||
BackupV1alpha1Api,
|
||||
CacheV1alpha1ConsoleApi,
|
||||
CategoryV1alpha1Api,
|
||||
CommentV1alpha1Api,
|
||||
CommentV1alpha1ConsoleApi,
|
||||
|
@ -277,7 +276,6 @@ function createConsoleApiClient(axiosInstance: AxiosInstance) {
|
|||
baseURL,
|
||||
axiosInstance
|
||||
),
|
||||
cache: new CacheV1alpha1ConsoleApi(undefined, baseURL, axiosInstance),
|
||||
login: new LoginApi(undefined, baseURL, axiosInstance),
|
||||
storage: {
|
||||
attachment: new AttachmentV1alpha1ConsoleApi(
|
||||
|
|
|
@ -9,7 +9,6 @@ api/attachment-v1alpha1-uc-api.ts
|
|||
api/auth-provider-v1alpha1-api.ts
|
||||
api/auth-provider-v1alpha1-console-api.ts
|
||||
api/backup-v1alpha1-api.ts
|
||||
api/cache-v1alpha1-console-api.ts
|
||||
api/category-v1alpha1-api.ts
|
||||
api/category-v1alpha1-public-api.ts
|
||||
api/comment-v1alpha1-api.ts
|
||||
|
|
|
@ -22,7 +22,6 @@ export * from './api/attachment-v1alpha1-uc-api';
|
|||
export * from './api/auth-provider-v1alpha1-api';
|
||||
export * from './api/auth-provider-v1alpha1-console-api';
|
||||
export * from './api/backup-v1alpha1-api';
|
||||
export * from './api/cache-v1alpha1-console-api';
|
||||
export * from './api/category-v1alpha1-api';
|
||||
export * from './api/category-v1alpha1-public-api';
|
||||
export * from './api/comment-v1alpha1-api';
|
||||
|
|
|
@ -162,11 +162,6 @@ core:
|
|||
This operation will recreate search engine indexes for all
|
||||
published posts.
|
||||
success_message: Refresh search engine index successfully.
|
||||
evict_page_cache:
|
||||
title: Refresh Page Cache
|
||||
dialog_title: Refresh the page cache
|
||||
dialog_content: This operation will clear the cache for all pages.
|
||||
success_message: Refresh page cache successfully.
|
||||
user_stats:
|
||||
title: Users
|
||||
comment_stats:
|
||||
|
|
|
@ -158,11 +158,6 @@ core:
|
|||
dialog_title: 刷新搜索引擎索引
|
||||
dialog_content: 此操作会对所有已发布的文章重新创建本地搜索引擎的索引。
|
||||
success_message: 刷新成功
|
||||
evict_page_cache:
|
||||
title: 刷新页面缓存
|
||||
dialog_title: 刷新页面缓存
|
||||
dialog_content: 此操作会清空所有页面的缓存。
|
||||
success_message: 刷新成功
|
||||
user_stats:
|
||||
title: 用户
|
||||
comment_stats:
|
||||
|
|
|
@ -158,11 +158,6 @@ core:
|
|||
dialog_title: 刷新搜尋引擎索引
|
||||
dialog_content: 此操作會對所有已發佈的文章重新創建本地搜尋引擎的索引。
|
||||
success_message: 刷新成功
|
||||
evict_page_cache:
|
||||
title: 重新整理頁面快取
|
||||
dialog_title: 整理頁面快取
|
||||
dialog_content: 這個操作會清空所有頁面的快取。
|
||||
success_message: 刷新成功
|
||||
user_stats:
|
||||
title: 用戶
|
||||
comment_stats:
|
||||
|
|
Loading…
Reference in New Issue