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:
|
titles:
|
||||||
install: Install theme
|
install: Install theme
|
||||||
upgrade: Upgrade theme ({display_name})
|
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:
|
tabs:
|
||||||
local: Local
|
local: Local
|
||||||
remote:
|
remote:
|
||||||
|
|
|
@ -606,6 +606,10 @@ core:
|
||||||
titles:
|
titles:
|
||||||
install: 安装主题
|
install: 安装主题
|
||||||
upgrade: 升级主题({display_name})
|
upgrade: 升级主题({display_name})
|
||||||
|
operations:
|
||||||
|
existed_during_installation:
|
||||||
|
title: 主题已存在
|
||||||
|
description: 当前安装的主题已存在,是否升级?
|
||||||
tabs:
|
tabs:
|
||||||
local: 本地上传
|
local: 本地上传
|
||||||
remote:
|
remote:
|
||||||
|
|
|
@ -606,6 +606,10 @@ core:
|
||||||
titles:
|
titles:
|
||||||
install: 安裝主題
|
install: 安裝主題
|
||||||
upgrade: 升級主題({display_name})
|
upgrade: 升級主題({display_name})
|
||||||
|
operations:
|
||||||
|
existed_during_installation:
|
||||||
|
title: 主題已存在
|
||||||
|
description: 當前安裝的主題已存在,是否升級?
|
||||||
tabs:
|
tabs:
|
||||||
local: 本地上傳
|
local: 本地上傳
|
||||||
remote:
|
remote:
|
||||||
|
|
|
@ -356,7 +356,6 @@ watch(
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
v-model:visible="themeUploadVisible"
|
v-model:visible="themeUploadVisible"
|
||||||
:upgrade-theme="themeToUpgrade"
|
:upgrade-theme="themeToUpgrade"
|
||||||
@close="refetch"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ThemePreviewModal
|
<ThemePreviewModal
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<script lang="ts" setup>
|
<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 UppyUpload from "@/components/upload/UppyUpload.vue";
|
||||||
import { computed, ref, watch, nextTick } from "vue";
|
import { computed, ref, watch, nextTick } from "vue";
|
||||||
import type { Theme } from "@halo-dev/api-client";
|
import type { Theme } from "@halo-dev/api-client";
|
||||||
|
@ -9,6 +16,8 @@ import { useThemeStore } from "@/stores/theme";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import { submitForm } from "@formkit/core";
|
import { submitForm } from "@formkit/core";
|
||||||
|
import type { ErrorResponse } from "@uppy/core";
|
||||||
|
import type { UppyFile } from "@uppy/utils";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
@ -83,6 +92,71 @@ const onUploaded = () => {
|
||||||
handleVisibleChange(false);
|
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
|
// remote download
|
||||||
const activeTabId = ref("local");
|
const activeTabId = ref("local");
|
||||||
const remoteDownloadUrl = ref("");
|
const remoteDownloadUrl = ref("");
|
||||||
|
@ -120,10 +194,16 @@ const handleDownloadTheme = async () => {
|
||||||
|
|
||||||
handleVisibleChange(false);
|
handleVisibleChange(false);
|
||||||
|
|
||||||
routeRemoteDownloadUrl.value = null;
|
// eslint-disable-next-line
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.log("Failed to download theme", error);
|
const data = error?.response.data as ThemeInstallationErrorResponse;
|
||||||
|
if (data?.type === THEME_ALREADY_EXISTS_TYPE) {
|
||||||
|
handleCatchExistsException(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error("Failed to download theme", error);
|
||||||
} finally {
|
} finally {
|
||||||
|
routeRemoteDownloadUrl.value = null;
|
||||||
downloading.value = false;
|
downloading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -164,6 +244,7 @@ watch(
|
||||||
:endpoint="endpoint"
|
:endpoint="endpoint"
|
||||||
auto-proceed
|
auto-proceed
|
||||||
@uploaded="onUploaded"
|
@uploaded="onUploaded"
|
||||||
|
@error="onError"
|
||||||
/>
|
/>
|
||||||
</VTabItem>
|
</VTabItem>
|
||||||
<VTabItem
|
<VTabItem
|
||||||
|
|
Loading…
Reference in New Issue