Skip to main content

yggdrasil/pages/admin/system/backup/
row.rs

1use crate::api::database::backup::BackupInfo;
2use crate::components::ui::{
3    button_class, ButtonSize, ButtonVariant, ConfirmDialog, IconName, StatusDot,
4};
5use crate::utils::format_bytes;
6use leptos::prelude::*;
7
8/// 备份列表单行(抽取为子组件:各自 scope 内的确认框状态互不干扰)。
9///
10/// 恢复与删除先弹危险确认对话框,确认后回调父组件的 `on_restore` / `on_delete`。
11#[component]
12pub(super) fn BackupRow(
13    info: BackupInfo,
14    #[prop(into)] busy: Signal<bool>,
15    #[prop(into)] on_restore: Callback<String>,
16    #[prop(into)] on_delete: Callback<String>,
17) -> impl IntoView {
18    let fname_for_restore = info.filename.clone();
19    let fname_for_delete = info.filename.clone();
20
21    // 展示用派生值(纯计算)。
22    let dl_url = format!(
23        "/api/database/backups/{}",
24        super::super::urlencode(&info.filename)
25    );
26    let size_str = format_bytes(info.size_bytes as i64);
27    let (origin_label, origin_tone) = if info.origin == "auto" {
28        ("自动", "clay")
29    } else {
30        ("手动", "muted")
31    };
32    let uploads_dl = info.uploads_filename.as_ref().map(|f| {
33        (
34            format_bytes(info.uploads_size_bytes.unwrap_or(0) as i64),
35            format!("/api/database/backups/{}", super::super::urlencode(f)),
36        )
37    });
38    let up_size = uploads_dl.as_ref().map(|(size, _)| size.clone());
39    let up_url = uploads_dl.map(|(_, url)| url);
40
41    let confirm_restore = RwSignal::new(false);
42    let confirm_delete = RwSignal::new(false);
43    let restore_description = format!(
44        "现有数据会被「{}」覆盖。只恢复数据库,素材不随之还原,需要从配对的压缩包手动恢复。",
45        info.filename
46    );
47    let delete_description = format!("「{}」会从磁盘上删除,无法恢复。", info.filename);
48
49    view! {
50        <tr>
51            <td class="sys-mono">{info.filename.clone()}</td>
52            <td>
53                <StatusDot label=origin_label tone=origin_tone/>
54            </td>
55            <td class="admin-table-muted">{info.mode.clone()}</td>
56            <td class="admin-table-num">
57                {size_str}
58                {up_size.map(|up_size| view! { <div class="sys-sub">{format!("素材 {up_size}")}</div> })}
59            </td>
60            <td class="sys-row-actions">
61                <a
62                    class=button_class(ButtonVariant::Ghost, ButtonSize::Xs)
63                    href=dl_url
64                    rel="external"
65                    download=""
66                >
67                    "下载"
68                </a>
69                {up_url
70                    .map(|up_url| {
71                        view! {
72                            <a
73                                class=button_class(ButtonVariant::Ghost, ButtonSize::Xs)
74                                href=up_url
75                                rel="external"
76                                download=""
77                            >
78                                "素材"
79                            </a>
80                        }
81                    })}
82                <button
83                    class=button_class(ButtonVariant::Ghost, ButtonSize::Xs)
84                    type="button"
85                    disabled=move || busy.get()
86                    on:click=move |_| confirm_restore.set(true)
87                >
88                    "恢复"
89                </button>
90                <button
91                    class=format!("{} sys-danger", button_class(ButtonVariant::Ghost, ButtonSize::Xs))
92                    type="button"
93                    disabled=move || busy.get()
94                    on:click=move |_| confirm_delete.set(true)
95                >
96                    "删除"
97                </button>
98                <ConfirmDialog
99                    visible=confirm_restore
100                    title="用这份备份恢复数据库?"
101                    description=restore_description
102                    confirm_label="确认恢复"
103                    icon=IconName::RotateCcw
104                    on_confirm=move |_| on_restore.run(fname_for_restore.clone())
105                />
106                <ConfirmDialog
107                    visible=confirm_delete
108                    title="删除这份备份?"
109                    description=delete_description
110                    confirm_label="确认删除"
111                    on_confirm=move |_| on_delete.run(fname_for_delete.clone())
112                />
113            </td>
114        </tr>
115    }
116}