refactor: move update pipeline into dialog
This commit is contained in:
@@ -273,6 +273,7 @@ export default function UpdatePage({
|
|||||||
const [actionBusy, setActionBusy] = useState(false);
|
const [actionBusy, setActionBusy] = useState(false);
|
||||||
const [reloadReady, setReloadReady] = useState(false);
|
const [reloadReady, setReloadReady] = useState(false);
|
||||||
const [showNotesDialog, setShowNotesDialog] = useState(false);
|
const [showNotesDialog, setShowNotesDialog] = useState(false);
|
||||||
|
const [showPipelineDialog, setShowPipelineDialog] = useState(false);
|
||||||
const [now, setNow] = useState(() => Date.now());
|
const [now, setNow] = useState(() => Date.now());
|
||||||
|
|
||||||
const announced = useRef<string | null>(null);
|
const announced = useRef<string | null>(null);
|
||||||
@@ -338,6 +339,10 @@ export default function UpdatePage({
|
|||||||
}, [isMock]);
|
}, [isMock]);
|
||||||
|
|
||||||
const job = info?.job;
|
const job = info?.job;
|
||||||
|
useEffect(() => {
|
||||||
|
if (job && activeStatuses.has(job.status)) setShowPipelineDialog(true);
|
||||||
|
}, [job?.id, job?.status]);
|
||||||
|
|
||||||
const applyQueuedAt = timestamp(job?.applyQueuedAt);
|
const applyQueuedAt = timestamp(job?.applyQueuedAt);
|
||||||
const restartAt =
|
const restartAt =
|
||||||
timestamp(job?.restartDeadline) ??
|
timestamp(job?.restartDeadline) ??
|
||||||
@@ -468,6 +473,7 @@ export default function UpdatePage({
|
|||||||
mockTimer.current = null;
|
mockTimer.current = null;
|
||||||
setActionBusy(false);
|
setActionBusy(false);
|
||||||
setConfirmVersion(null);
|
setConfirmVersion(null);
|
||||||
|
setShowPipelineDialog(true);
|
||||||
if (confirmAction === "download") {
|
if (confirmAction === "download") {
|
||||||
handleScenarioChange("downloading_30");
|
handleScenarioChange("downloading_30");
|
||||||
notify?.("Mock:开始模拟下载,状态已流转至 [下载中]", "info");
|
notify?.("Mock:开始模拟下载,状态已流转至 [下载中]", "info");
|
||||||
@@ -496,6 +502,7 @@ export default function UpdatePage({
|
|||||||
setConfirmVersion(null);
|
setConfirmVersion(null);
|
||||||
setReloadReady(false);
|
setReloadReady(false);
|
||||||
setLiveInfo((current) => (current ? { ...current, job: result.job } : current));
|
setLiveInfo((current) => (current ? { ...current, job: result.job } : current));
|
||||||
|
setShowPipelineDialog(true);
|
||||||
notify?.(
|
notify?.(
|
||||||
confirmAction === "download" ? "更新包下载已开始" : "更新已开始,服务会短暂重启",
|
confirmAction === "download" ? "更新包下载已开始" : "更新已开始,服务会短暂重启",
|
||||||
"info"
|
"info"
|
||||||
@@ -715,11 +722,18 @@ export default function UpdatePage({
|
|||||||
</Surface>
|
</Surface>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stepper Process Card */}
|
{/* Stepper Process Dialog */}
|
||||||
<Surface className="tn-stepper-surface">
|
<Dialog
|
||||||
|
visible={showPipelineDialog}
|
||||||
|
header="版本升级流水线"
|
||||||
|
confirmBtn={{ content: "关闭", theme: "default" }}
|
||||||
|
cancelBtn={null}
|
||||||
|
onConfirm={() => setShowPipelineDialog(false)}
|
||||||
|
onClose={() => setShowPipelineDialog(false)}
|
||||||
|
>
|
||||||
|
<div className="tn-stepper-surface">
|
||||||
<div className="tn-stepper-head">
|
<div className="tn-stepper-head">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="tn-section-heading">版本升级流水线</h3>
|
|
||||||
<small className="tn-section-subheading">
|
<small className="tn-section-subheading">
|
||||||
标准化发布流程:版本发现 → 校验签名与清单 → 安全暂存 → 原子切换并重启
|
标准化发布流程:版本发现 → 校验签名与清单 → 安全暂存 → 原子切换并重启
|
||||||
</small>
|
</small>
|
||||||
@@ -834,7 +848,8 @@ export default function UpdatePage({
|
|||||||
<span>更新成功完成!新版本已通过内置端点健康检查,账本数据与附件完整无损。</span>
|
<span>更新成功完成!新版本已通过内置端点健康检查,账本数据与附件完整无损。</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
{/* Release Details Section */}
|
{/* Release Details Section */}
|
||||||
{latest ? (
|
{latest ? (
|
||||||
@@ -856,32 +871,8 @@ export default function UpdatePage({
|
|||||||
</small>
|
</small>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="tn-release-header-actions">
|
|
||||||
{notes && (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="medium"
|
|
||||||
onClick={() => setShowNotesDialog(true)}
|
|
||||||
icon={<FileCode size={15} />}
|
|
||||||
>
|
|
||||||
查看完整更新日志
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Release Notes Preview snippet */}
|
|
||||||
{notes && (
|
|
||||||
<div className="tn-release-notes-box">
|
|
||||||
<div className="tn-release-notes-heading">
|
|
||||||
<span>更新内容概览</span>
|
|
||||||
</div>
|
|
||||||
<div className="tn-release-notes-content">
|
|
||||||
<MarkdownNotes value={notes} compact />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Integrity & compatibility facts grid */}
|
{/* Integrity & compatibility facts grid */}
|
||||||
<div className="tn-facts-grid">
|
<div className="tn-facts-grid">
|
||||||
<div className="tn-fact-item">
|
<div className="tn-fact-item">
|
||||||
@@ -963,6 +954,30 @@ export default function UpdatePage({
|
|||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{latest && notes && (
|
||||||
|
<Surface className="tn-release-notes-surface">
|
||||||
|
<div className="tn-release-notes-header">
|
||||||
|
<div>
|
||||||
|
<span className="tn-eyebrow">更新日志</span>
|
||||||
|
<h3 className="tn-section-heading">本次版本更新内容</h3>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="medium"
|
||||||
|
onClick={() => setShowNotesDialog(true)}
|
||||||
|
icon={<FileCode size={15} />}
|
||||||
|
>
|
||||||
|
查看完整日志
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="tn-release-notes-box">
|
||||||
|
<div className="tn-release-notes-content">
|
||||||
|
<MarkdownNotes value={notes} compact />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Surface>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Manual source warning if not systemd */}
|
{/* Manual source warning if not systemd */}
|
||||||
{!info.configured && (
|
{!info.configured && (
|
||||||
<div className="tn-update-explainer">
|
<div className="tn-update-explainer">
|
||||||
|
|||||||
@@ -847,6 +847,17 @@ input:focus-visible, textarea:focus-visible, select:focus-visible {
|
|||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
.tn-release-notes-surface {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.tn-release-notes-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
.tn-release-header {
|
.tn-release-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -870,7 +881,7 @@ input:focus-visible, textarea:focus-visible, select:focus-visible {
|
|||||||
color: var(--tn-text-secondary);
|
color: var(--tn-text-secondary);
|
||||||
}
|
}
|
||||||
.tn-release-notes-box {
|
.tn-release-notes-box {
|
||||||
margin: 16px 0;
|
margin: 0;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
border: 1px solid var(--tn-border);
|
border: 1px solid var(--tn-border);
|
||||||
@@ -1064,6 +1075,13 @@ input:focus-visible, textarea:focus-visible, select:focus-visible {
|
|||||||
.tn-release-header {
|
.tn-release-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
.tn-release-notes-header {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.tn-release-notes-header .t-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
.tn-release-card-actions {
|
.tn-release-card-actions {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Reference in New Issue
Block a user