1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! The list state a request's list page shows, which [`list_query`] reads for its widgets.
use ;
use ;
use ;
use crate::;
/// The resource whose list page the request renders, and the state that page shows. The panel
/// puts an empty one on each request, and the list page fills it before its widgets render.
pub >>);
/// `R`'s records as its list shows them in this request: the [`scoped_query`](crate::scoped_query)
/// the list reads, narrowed by its tab, search and filters, unordered. A
/// [`list_widget`](crate::ResourceDef::list_widget) reading it shows figures that follow the list,
/// and reruns with it as the reader searches, filters or switches tabs.
///
/// Outside `R`'s list page, as on a dashboard, it reads the list's first tab with no search or
/// filter. Like the list, it leaves out a filter it cannot apply, and the trashed records unless
/// the list's trash control asks for them. Count what it selects with
/// [`db::count`](crate::db::count).
///
/// ```rust,no_run
/// # #[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns)]
/// # struct Post { #[key] #[auto] id: uuid::Uuid, title: String, published: bool }
/// # struct PostResource;
/// # impl tablo_core::Resource for PostResource {
/// # type Model = Post;
/// # type Form = tablo_core::NoForm<Post>;
/// # fn declare() -> tablo_core::ResourceDef<Self> { tablo_core::ResourceDef::new() }
/// # }
/// use tablo_core::{Stat, Widget, db, list_query};
/// use topcoat::{Result, context::Cx, view::View};
///
/// struct Published;
///
/// impl Widget for Published {
/// async fn render(cx: &Cx) -> Result<impl View> {
/// let published = list_query::<PostResource>(cx)
/// .await?
/// .filter(Post::fields().published().eq(true));
/// let count = db::count(cx, published).await?;
/// Ok(tablo_core::stats(
/// cx,
/// vec![Stat::new("Published", count.to_string())],
/// ))
/// }
/// }
/// ```
///
/// A tab and a filter can ask one column for two values. Toasty then folds the query's filter to
/// `false`, and panics planning an `include` over it: count the query, or ask it for a row, before
/// loading its rows with their relations.
///
/// # Errors
///
/// 403 when the request may not open `R`'s list, the check [`can_list`](crate::can_list) makes,
/// which fails the whole page the widget is on: a widget on another page asks `can_list` first.
/// The database failing a filter's check.
pub async