diff --git a/api-docs/openapi/v3_0/aggregated.json b/api-docs/openapi/v3_0/aggregated.json index f5a069f94..4237b2709 100644 --- a/api-docs/openapi/v3_0/aggregated.json +++ b/api-docs/openapi/v3_0/aggregated.json @@ -4231,6 +4231,30 @@ ] } }, + "/apis/api.console.halo.run/v1alpha1/themes/{name}/invalidate-cache": { + "put": { + "description": "Invalidate theme template cache.", + "operationId": "InvalidateCache", + "parameters": [ + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content" + } + }, + "tags": [ + "api.console.halo.run/v1alpha1/Theme" + ] + } + }, "/apis/api.console.halo.run/v1alpha1/themes/{name}/reload": { "put": { "description": "Reload theme setting.", diff --git a/application/src/main/java/run/halo/app/core/extension/theme/ThemeEndpoint.java b/application/src/main/java/run/halo/app/core/extension/theme/ThemeEndpoint.java index a4fdda478..6b395fc56 100644 --- a/application/src/main/java/run/halo/app/core/extension/theme/ThemeEndpoint.java +++ b/application/src/main/java/run/halo/app/core/extension/theme/ThemeEndpoint.java @@ -6,6 +6,7 @@ import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder; +import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -188,6 +189,20 @@ public class ThemeEndpoint implements CustomEndpoint { .response(responseBuilder() .implementation(Theme.class)) ) + .PUT("/themes/{name}/invalidate-cache", this::invalidateCache, + builder -> builder.operationId("InvalidateCache") + .description("Invalidate theme template cache.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.PATH) + .required(true) + .implementation(String.class) + ) + .response(responseBuilder() + .responseCode(String.valueOf(NO_CONTENT.value())) + ) + ) .GET("themes", this::listThemes, builder -> { builder.operationId("ListThemes") @@ -234,6 +249,13 @@ public class ThemeEndpoint implements CustomEndpoint { .build(); } + private Mono invalidateCache(ServerRequest request) { + final var name = request.pathVariable("name"); + return client.get(Theme.class, name) + .flatMap(theme -> templateEngineManager.clearCache(name)) + .then(ServerResponse.noContent().build()); + } + private Mono upgradeFromUri(ServerRequest request) { final var name = request.pathVariable("name"); var content = request.bodyToMono(UpgradeFromUriRequest.class) diff --git a/application/src/main/resources/extensions/role-template-theme.yaml b/application/src/main/resources/extensions/role-template-theme.yaml index 1c10530e6..6b6c375bf 100644 --- a/application/src/main/resources/extensions/role-template-theme.yaml +++ b/application/src/main/resources/extensions/role-template-theme.yaml @@ -16,7 +16,7 @@ rules: verbs: [ "*" ] - apiGroups: [ "api.console.halo.run" ] resources: [ "themes", "themes/reload", "themes/resetconfig", "themes/config", "themes/activation", - "themes/install-from-uri", "themes/upgrade-from-uri" ] + "themes/install-from-uri", "themes/upgrade-from-uri", "themes/invalidate-cache" ] verbs: [ "*" ] - nonResourceURLs: [ "/apis/api.console.halo.run/themes/install" ] verbs: [ "create" ] diff --git a/ui/console-src/modules/interface/themes/ThemeDetail.vue b/ui/console-src/modules/interface/themes/ThemeDetail.vue index de0d3cc70..07792ea01 100644 --- a/ui/console-src/modules/interface/themes/ThemeDetail.vue +++ b/ui/console-src/modules/interface/themes/ThemeDetail.vue @@ -32,6 +32,27 @@ const themesModal = inject>("themesModal"); const { isActivated, getFailedMessage, handleResetSettingConfig } = useThemeLifeCycle(selectedTheme); +async function handleClearCache() { + Dialog.warning({ + title: t("core.theme.operations.clear_templates_cache.title"), + description: t("core.theme.operations.clear_templates_cache.description"), + confirmText: t("core.common.buttons.confirm"), + cancelText: t("core.common.buttons.cancel"), + async onConfirm() { + if (!selectedTheme.value) { + console.error("No selected or activated theme"); + return; + } + + await apiClient.theme.invalidateCache({ + name: selectedTheme.value?.metadata.name, + }); + + Toast.success(t("core.common.toast.operation_success")); + }, + }); +} + const handleReloadTheme = async () => { Dialog.warning({ title: t("core.theme.operations.reload.title"), @@ -109,6 +130,9 @@ const handleReloadTheme = async () => { {{ $t("core.theme.operations.reload.button") }} + + {{ $t("core.theme.operations.clear_templates_cache.button") }} + {{ $t("core.common.buttons.reset") }} diff --git a/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-theme-api.ts b/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-theme-api.ts index 8865bf7aa..2ebbec602 100644 --- a/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-theme-api.ts +++ b/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-theme-api.ts @@ -279,6 +279,47 @@ export const ApiConsoleHaloRunV1alpha1ThemeApiAxiosParamCreator = function (conf options: localVarRequestOptions, }; }, + /** + * Invalidate theme template cache. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + invalidateCache: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('invalidateCache', 'name', name) + const localVarPath = `/apis/api.console.halo.run/v1alpha1/themes/{name}/invalidate-cache` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication BasicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication BearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * List themes. * @param {number} [page] Page number. Default is 0. @@ -649,6 +690,18 @@ export const ApiConsoleHaloRunV1alpha1ThemeApiFp = function(configuration?: Conf const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1ThemeApi.installThemeFromUri']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * Invalidate theme template cache. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async invalidateCache(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.invalidateCache(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1ThemeApi.invalidateCache']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * List themes. * @param {number} [page] Page number. Default is 0. @@ -790,6 +843,15 @@ export const ApiConsoleHaloRunV1alpha1ThemeApiFactory = function (configuration? installThemeFromUri(requestParameters: ApiConsoleHaloRunV1alpha1ThemeApiInstallThemeFromUriRequest, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.installThemeFromUri(requestParameters.installFromUriRequest, options).then((request) => request(axios, basePath)); }, + /** + * Invalidate theme template cache. + * @param {ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + invalidateCache(requestParameters: ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.invalidateCache(requestParameters.name, options).then((request) => request(axios, basePath)); + }, /** * List themes. * @param {ApiConsoleHaloRunV1alpha1ThemeApiListThemesRequest} requestParameters Request parameters. @@ -903,6 +965,20 @@ export interface ApiConsoleHaloRunV1alpha1ThemeApiInstallThemeFromUriRequest { readonly installFromUriRequest: InstallFromUriRequest } +/** + * Request parameters for invalidateCache operation in ApiConsoleHaloRunV1alpha1ThemeApi. + * @export + * @interface ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest + */ +export interface ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest { + /** + * + * @type {string} + * @memberof ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCache + */ + readonly name: string +} + /** * Request parameters for listThemes operation in ApiConsoleHaloRunV1alpha1ThemeApi. * @export @@ -1107,6 +1183,17 @@ export class ApiConsoleHaloRunV1alpha1ThemeApi extends BaseAPI { return ApiConsoleHaloRunV1alpha1ThemeApiFp(this.configuration).installThemeFromUri(requestParameters.installFromUriRequest, options).then((request) => request(this.axios, this.basePath)); } + /** + * Invalidate theme template cache. + * @param {ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ApiConsoleHaloRunV1alpha1ThemeApi + */ + public invalidateCache(requestParameters: ApiConsoleHaloRunV1alpha1ThemeApiInvalidateCacheRequest, options?: RawAxiosRequestConfig) { + return ApiConsoleHaloRunV1alpha1ThemeApiFp(this.configuration).invalidateCache(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + /** * List themes. * @param {ApiConsoleHaloRunV1alpha1ThemeApiListThemesRequest} requestParameters Request parameters. diff --git a/ui/src/locales/en.yaml b/ui/src/locales/en.yaml index 96130625f..2fc98e557 100644 --- a/ui/src/locales/en.yaml +++ b/ui/src/locales/en.yaml @@ -708,6 +708,12 @@ core: existed_during_installation: title: The theme already exists. description: The currently installed theme already exists, do you want to upgrade? + clear_templates_cache: + button: Clear templates cache + title: Clear templates cache + description: >- + This feature allows you to refresh the cache to view the latest web + results after modifying template files at runtime. list_modal: tabs: installed: Installed diff --git a/ui/src/locales/zh-CN.yaml b/ui/src/locales/zh-CN.yaml index 43b4cc878..253e43cef 100644 --- a/ui/src/locales/zh-CN.yaml +++ b/ui/src/locales/zh-CN.yaml @@ -680,6 +680,10 @@ core: existed_during_installation: title: 主题已存在 description: 当前安装的主题已存在,是否升级? + clear_templates_cache: + button: 清理模板缓存 + title: 清除模板缓存 + description: 此功能适用于在运行时修改模板文件后,刷新缓存以查看最新网页结果。 list_modal: tabs: installed: 已安装 diff --git a/ui/src/locales/zh-TW.yaml b/ui/src/locales/zh-TW.yaml index ddc61d1d6..9869df726 100644 --- a/ui/src/locales/zh-TW.yaml +++ b/ui/src/locales/zh-TW.yaml @@ -660,6 +660,10 @@ core: existed_during_installation: title: 主題已存在 description: 當前安裝的主題已存在,是否升級? + clear_templates_cache: + button: 清除模板快取 + title: 清除模板快取 + description: 此功能適用於在運行時修改模板檔案後,刷新快取以查看最新網頁結果。 list_modal: tabs: installed: 已安裝