mirror of https://github.com/halo-dev/halo
feat: prompt to upgrade theme when installing existing theme (#3970)
#### What type of PR is this? /kind feature /area console /milestone 2.6.x #### What this PR does / why we need it: 支持在安装已存在主题时提示是否升级主题。 <img width="611" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/2e99c781-96b6-4900-9a37-2d472ad65411"> <img width="604" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/a7bfa9d8-1522-417f-91b4-6ea3f75f693e"> #### Which issue(s) this PR fixes: Fixes #3969 #### Special notes for your reviewer: 测试方式: 1. 通过本地上传和远程下载的方式重复安装某个主题,观察是否可以正常提示升级以及测试升级是否正常。 #### Does this PR introduce a user-facing change? ```release-note Console 端支持安装已存在主题时提示升级主题。 ```pull/3983/head^2
parent
6dd98d2c0c
commit
533f0cfa66
|
@ -606,6 +606,10 @@ core:
|
|||
titles:
|
||||
install: Install theme
|
||||
upgrade: Upgrade theme ({display_name})
|
||||
operations:
|
||||
existed_during_installation:
|
||||
title: The theme already exists.
|
||||
description: The currently installed theme already exists, do you want to upgrade?
|
||||
tabs:
|
||||
local: Local
|
||||
remote:
|
||||
|
|
|
@ -606,6 +606,10 @@ core:
|
|||
titles:
|
||||
install: 安装主题
|
||||
upgrade: 升级主题({display_name})
|
||||
operations:
|
||||
existed_during_installation:
|
||||
title: 主题已存在
|
||||
description: 当前安装的主题已存在,是否升级?
|
||||
tabs:
|
||||
local: 本地上传
|
||||
remote:
|
||||
|
|
|
@ -606,6 +606,10 @@ core:
|
|||
titles:
|
||||
install: 安裝主題
|
||||
upgrade: 升級主題({display_name})
|
||||
operations:
|
||||
existed_during_installation:
|
||||
title: 主題已存在
|
||||
description: 當前安裝的主題已存在,是否升級?
|
||||
tabs:
|
||||
local: 本地上傳
|
||||
remote:
|
||||
|
|
|
@ -356,7 +356,6 @@ watch(
|
|||
v-if="visible"
|
||||
v-model:visible="themeUploadVisible"
|
||||
:upgrade-theme="themeToUpgrade"
|
||||
@close="refetch"
|
||||
/>
|
||||
|
||||
<ThemePreviewModal
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<script lang="ts" setup>
|
||||
import { Toast, VButton, VModal, VTabItem, VTabs } from "@halo-dev/components";
|
||||
import {
|
||||
Dialog,
|
||||
Toast,
|
||||
VButton,
|
||||
VModal,
|
||||
VTabItem,
|
||||
VTabs,
|
||||
} from "@halo-dev/components";
|
||||
import UppyUpload from "@/components/upload/UppyUpload.vue";
|
||||
import { computed, ref, watch, nextTick } from "vue";
|
||||
import type { Theme } from "@halo-dev/api-client";
|
||||
|
@ -9,6 +16,8 @@ import { useThemeStore } from "@/stores/theme";
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import { submitForm } from "@formkit/core";
|
||||
import type { ErrorResponse } from "@uppy/core";
|
||||
import type { UppyFile } from "@uppy/utils";
|
||||
|
||||
const { t } = useI18n();
|
||||
const queryClient = useQueryClient();
|
||||
|
@ -83,6 +92,71 @@ const onUploaded = () => {
|
|||
handleVisibleChange(false);
|
||||
};
|
||||
|
||||
interface ThemeInstallationErrorResponse {
|
||||
detail: string;
|
||||
instance: string;
|
||||
themeName: string;
|
||||
requestId: string;
|
||||
status: number;
|
||||
timestamp: string;
|
||||
title: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
const THEME_ALREADY_EXISTS_TYPE = "https://halo.run/probs/theme-alreay-exists";
|
||||
|
||||
const onError = (file: UppyFile<unknown>, response: ErrorResponse) => {
|
||||
const body = response.body as ThemeInstallationErrorResponse;
|
||||
|
||||
if (body.type === THEME_ALREADY_EXISTS_TYPE) {
|
||||
handleCatchExistsException(body, file.data as File);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCatchExistsException = async (
|
||||
error: ThemeInstallationErrorResponse,
|
||||
file?: File
|
||||
) => {
|
||||
Dialog.info({
|
||||
title: t(
|
||||
"core.theme.upload_modal.operations.existed_during_installation.title"
|
||||
),
|
||||
description: t(
|
||||
"core.theme.upload_modal.operations.existed_during_installation.description"
|
||||
),
|
||||
confirmText: t("core.common.buttons.confirm"),
|
||||
cancelText: t("core.common.buttons.cancel"),
|
||||
onConfirm: async () => {
|
||||
if (activeTabId.value === "local") {
|
||||
if (!file) {
|
||||
throw new Error("File is required");
|
||||
}
|
||||
|
||||
await apiClient.theme.upgradeTheme({
|
||||
name: error.themeName,
|
||||
file: file,
|
||||
});
|
||||
} else if (activeTabId.value === "remote") {
|
||||
await apiClient.theme.upgradeThemeFromUri({
|
||||
name: error.themeName,
|
||||
upgradeFromUriRequest: {
|
||||
uri: remoteDownloadUrl.value,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw new Error("Unknown tab id");
|
||||
}
|
||||
|
||||
Toast.success(t("core.common.toast.upgrade_success"));
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["themes"] });
|
||||
themeStore.fetchActivatedTheme();
|
||||
|
||||
handleVisibleChange(false);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// remote download
|
||||
const activeTabId = ref("local");
|
||||
const remoteDownloadUrl = ref("");
|
||||
|
@ -120,10 +194,16 @@ const handleDownloadTheme = async () => {
|
|||
|
||||
handleVisibleChange(false);
|
||||
|
||||
routeRemoteDownloadUrl.value = null;
|
||||
} catch (error) {
|
||||
console.log("Failed to download theme", error);
|
||||
// eslint-disable-next-line
|
||||
} catch (error: any) {
|
||||
const data = error?.response.data as ThemeInstallationErrorResponse;
|
||||
if (data?.type === THEME_ALREADY_EXISTS_TYPE) {
|
||||
handleCatchExistsException(data);
|
||||
}
|
||||
|
||||
console.error("Failed to download theme", error);
|
||||
} finally {
|
||||
routeRemoteDownloadUrl.value = null;
|
||||
downloading.value = false;
|
||||
}
|
||||
};
|
||||
|
@ -164,6 +244,7 @@ watch(
|
|||
:endpoint="endpoint"
|
||||
auto-proceed
|
||||
@uploaded="onUploaded"
|
||||
@error="onError"
|
||||
/>
|
||||
</VTabItem>
|
||||
<VTabItem
|
||||
|
|
Loading…
Reference in New Issue