Skip to content

視窗與內容區塊

app.open(title) 會回傳一個 Window。透過 win.blocks() 填充它;每個方法都會附加一個內容區塊,並回傳一個具型別的控制柄,供你保留以便日後更新。

內容區塊類型

方法控制柄適用於
fields([(label, value), …])FieldsHandle帶標籤的鍵/值狀態——表單、詳情面板
table(columns, rows)TableHandle結構一致的記錄
list(items) / ordered_listListHandle序列
text(s)TextHandle敘述文字、摘要
notice(severity, text)NoticeHandle驗證與狀態訊息
media(mime, url)MediaHandle圖片、圖表、螢幕擷圖
custom(payload)BlockHandle任何實作 Serialize 且不屬於其他種類的內容
rust
let win = app.open("Inbox");
win.set_summary("12 unread");

let stats  = win.blocks().fields([("Unread", 12), ("Total", 340)]);
let mail   = win.blocks().table(["From", "Subject"], vec![vec!["ops", "Deploy done"]]);
let banner = win.blocks().notice(Severity::Info, "Syncing…");

讓投影保持最新

每一次控制柄方法呼叫都是一次投影更新:版本遞增與客戶端通知都會自動完成。請在你 UI 的變更事件裡呼叫它們。

rust
fn on_recipient_changed(form: &FieldsHandle, win: &Window, value: &str) {
    form.set("Recipient", value);  // any Serialize value; auto version++ + notify
    win.set_summary(if value.is_empty() { "…recipient empty" } else { "…ready" });
}

單一同步入口的習慣

只要狀態不只是單一純量,就寫一個方法來鏡射當前狀態,並在每次變更之後呼叫它。這正是讓偏離不可能發生的關鍵:

rust
impl Todos {
    /// The only place the projection is written.
    fn sync(&self) {
        self.table.clear_rows();
        for (i, t) in self.items.iter().enumerate() {
            self.table.push_row([
                (i + 1).to_string(),
                t.text.clone(),
                if t.done { "done" } else { "open" }.to_string(),
            ]);
        }
    }

    /// Mutate, then sync — the one path buttons and agent actions share.
    fn mutate(&mut self, f: impl FnOnce(&mut Self)) {
        f(self);
        self.sync();
    }
}

欄位是 upsert 語意

當標籤不存在時,FieldsHandle::set 會附加一個新欄位,而不是回報錯誤。這讓投影可以動態增加欄位——但也意味著打錯字時會靜默地多出一個欄位,而不會失敗。

大型集合

不要把數千列資料都投影出去。只鏡射其中一頁,並用 table_truncated / list_truncated 宣告該視窗,好讓 Agent 知道它看到的只是一個切片:

rust
// rows[offset .. offset+PAGE] out of `total` overall
let log = win.blocks().table_truncated(["Seq", "Kind"], page_rows, offset, total);

// Later, after the underlying data changed:
log.set_truncation(new_offset, new_total);

注意

push_row 不會調整 total。在已截斷的內容區塊上,每當真實總數改變時,都要用 set_truncation 重新宣告一次。

敏感值

只需標記欄位一次;之後你就像寫其他欄位一樣寫入它,Purview 會在輸出時將其遮蔽:

rust
let f = win.blocks().fields([("Account", "")]);
f.set_sensitive("Account", true);
f.set("Account", "12345678"); // mirrored, but never exposed in app://windows

單向操作

清除標記並不會還原明文——之後請重新設定一個新值。