fix: 修复更新下载请求缺少确认参数导致报错、增加弹窗内嵌显式错误条、统一全站通知弹窗右上角对齐
TallyNote release / linux-x64 (push) Successful in 7m23s
TallyNote release / linux-x64 (push) Successful in 7m23s
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tallynote",
|
"name": "tallynote",
|
||||||
"version": "1.1.38",
|
"version": "1.1.39",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@9.0.6",
|
"packageManager": "pnpm@9.0.6",
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ export const updateApplySchema = z.object({
|
|||||||
|
|
||||||
export const updateDownloadSchema = z.object({
|
export const updateDownloadSchema = z.object({
|
||||||
version: z.string().trim().regex(/^v?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/),
|
version: z.string().trim().regex(/^v?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/),
|
||||||
confirm: z.literal(true),
|
confirm: z.boolean().default(true).optional(),
|
||||||
}).strict();
|
}).strict();
|
||||||
|
|
||||||
export type ApiError = {
|
export type ApiError = {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function App() {
|
|||||||
const notify = useCallback((message: string, kind: "success" | "error" | "info" = "info") => {
|
const notify = useCallback((message: string, kind: "success" | "error" | "info" = "info") => {
|
||||||
// The placement container owns the responsive right inset. Keeping the
|
// The placement container owns the responsive right inset. Keeping the
|
||||||
// item offset at zero avoids pushing narrow-screen notices off canvas.
|
// item offset at zero avoids pushing narrow-screen notices off canvas.
|
||||||
const options = { content: message, duration: 4200, placement: "top-right" as const, offset: [0, 76] as [number, number], zIndex: 5000 };
|
const options = { content: message, duration: 4200, placement: "top-right" as const, offset: [24, 76] as [number, number], zIndex: 6000 };
|
||||||
const show = kind === "success" ? NotificationPlugin.success : kind === "error" ? NotificationPlugin.error : NotificationPlugin.info;
|
const show = kind === "success" ? NotificationPlugin.success : kind === "error" ? NotificationPlugin.error : NotificationPlugin.info;
|
||||||
void show(options);
|
void show(options);
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ export default function UpdatePage({
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [checking, setChecking] = useState(false);
|
const [checking, setChecking] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
const [modalError, setModalError] = useState("");
|
||||||
const [pollError, setPollError] = useState("");
|
const [pollError, setPollError] = useState("");
|
||||||
const [actionBusy, setActionBusy] = useState(false);
|
const [actionBusy, setActionBusy] = useState(false);
|
||||||
const [reloadReady, setReloadReady] = useState(false);
|
const [reloadReady, setReloadReady] = useState(false);
|
||||||
@@ -457,16 +458,20 @@ export default function UpdatePage({
|
|||||||
if (!latest) return;
|
if (!latest) return;
|
||||||
setActionBusy(true);
|
setActionBusy(true);
|
||||||
setError("");
|
setError("");
|
||||||
|
setModalError("");
|
||||||
try {
|
try {
|
||||||
const response = await api<{ job: UpdateJob }>("/api/update/download", {
|
const response = await api<{ job: UpdateJob }>("/api/update/download", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ version: latest.version }),
|
body: JSON.stringify({ version: latest.version, confirm: true }),
|
||||||
});
|
});
|
||||||
setLiveInfo((current) => (current ? { ...current, job: response.job } : current));
|
setLiveInfo((current) => (current ? { ...current, job: response.job } : current));
|
||||||
setConfirmReadyToDownload(false);
|
setConfirmReadyToDownload(false);
|
||||||
notify?.("已提交下载更新包请求,后台下载中", "info");
|
notify?.("已提交下载更新包请求,后台下载中", "info");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError((e as Error).message);
|
const msg = (e as Error).message;
|
||||||
|
setError(msg);
|
||||||
|
setModalError(msg);
|
||||||
|
notify?.(msg, "error");
|
||||||
} finally {
|
} finally {
|
||||||
setActionBusy(false);
|
setActionBusy(false);
|
||||||
}
|
}
|
||||||
@@ -477,15 +482,19 @@ export default function UpdatePage({
|
|||||||
if (!latest) return;
|
if (!latest) return;
|
||||||
setActionBusy(true);
|
setActionBusy(true);
|
||||||
setError("");
|
setError("");
|
||||||
|
setModalError("");
|
||||||
try {
|
try {
|
||||||
const response = await api<{ job: UpdateJob }>("/api/update/apply", {
|
const response = await api<{ job: UpdateJob }>("/api/update/apply", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ version: latest.version, confirm: true }),
|
body: JSON.stringify({ version: latest.version, confirm: true, ...(job?.id ? { jobId: job.id } : {}) }),
|
||||||
});
|
});
|
||||||
setLiveInfo((current) => (current ? { ...current, job: response.job } : current));
|
setLiveInfo((current) => (current ? { ...current, job: response.job } : current));
|
||||||
notify?.("已提交升级请求,正在备份并平滑重启…", "info");
|
notify?.("已提交升级请求,正在备份并平滑重启…", "info");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError((e as Error).message);
|
const msg = (e as Error).message;
|
||||||
|
setError(msg);
|
||||||
|
setModalError(msg);
|
||||||
|
notify?.(msg, "error");
|
||||||
} finally {
|
} finally {
|
||||||
setActionBusy(false);
|
setActionBusy(false);
|
||||||
}
|
}
|
||||||
@@ -751,7 +760,7 @@ export default function UpdatePage({
|
|||||||
size="large"
|
size="large"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setConfirmReadyToDownload(true);
|
setConfirmReadyToDownload(true);
|
||||||
setShowUpgradeModal(true);
|
setModalError(""); setShowUpgradeModal(true);
|
||||||
}}
|
}}
|
||||||
disabled={actionBusy}
|
disabled={actionBusy}
|
||||||
icon={<Download size={16} />}
|
icon={<Download size={16} />}
|
||||||
@@ -834,6 +843,13 @@ export default function UpdatePage({
|
|||||||
onClose={() => setShowUpgradeModal(false)}
|
onClose={() => setShowUpgradeModal(false)}
|
||||||
>
|
>
|
||||||
<div className="tn-stepper-surface">
|
<div className="tn-stepper-surface">
|
||||||
|
{modalError && (
|
||||||
|
<div className="tn-modal-error-banner" role="alert">
|
||||||
|
<AlertCircle size={16} />
|
||||||
|
<span>{modalError}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 4 Steps Horizontal (Exact ASCII: (1) 版本确认 (2) 下载更新包 (3) 校验与准备 (4) 重启恢复) */}
|
{/* 4 Steps Horizontal (Exact ASCII: (1) 版本确认 (2) 下载更新包 (3) 校验与准备 (4) 重启恢复) */}
|
||||||
<div className="tn-stepper-wrap">
|
<div className="tn-stepper-wrap">
|
||||||
<Steps current={currentStep} theme="default">
|
<Steps current={currentStep} theme="default">
|
||||||
|
|||||||
@@ -116,7 +116,35 @@ input:focus-visible, textarea:focus-visible, select:focus-visible {
|
|||||||
transition: all 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
transition: all 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||||
}
|
}
|
||||||
.t-notification__show--top-right {
|
.t-notification__show--top-right {
|
||||||
right: 20px !important;
|
top: 76px !important;
|
||||||
|
right: 24px !important;
|
||||||
|
z-index: 6000 !important;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.t-notification__show--top-right {
|
||||||
|
top: 16px !important;
|
||||||
|
right: 16px !important;
|
||||||
|
left: 16px !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tn-modal-error-banner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 11px 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
color: #991b1b;
|
||||||
|
font-size: 13.5px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.tn-modal-error-banner svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 核心对齐修复:清除 TDesign 默认的 margin-top: 8px 导致的文字下沉不居中 */
|
/* 核心对齐修复:清除 TDesign 默认的 margin-top: 8px 导致的文字下沉不居中 */
|
||||||
|
|||||||
Reference in New Issue
Block a user