edc_web_components/components/
list_assets.rs1use crate::components::DatasetCard;
2use crate::models::{AssetItem, DataspaceDataset};
3use patternfly_yew::prelude::*;
4use std::rc::Rc;
5use yew::prelude::*;
6
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct ListAssetsProps {
9 pub asset_items: Vec<AssetItem>,
10 pub offset: usize,
11 pub limit: usize,
12 pub onoffset: Callback<usize>,
13 pub onlimit: Callback<usize>,
14 pub onshow: Callback<String>,
15 #[prop_or(AttrValue::Static("Select"))]
16 pub button_label: AttrValue,
17}
18
19#[component]
20pub fn ListAssets(props: &ListAssetsProps) -> Html {
21 let display_cards = use_state(|| true);
22 let total_entries: Option<usize> = None;
23
24 let nav_callback = use_callback(
25 (
26 props.offset,
27 props.limit,
28 total_entries,
29 props.onoffset.clone(),
30 ),
31 |page: Navigation, (offset, limit, total_entries, onoffset)| {
32 let offset = match page {
33 Navigation::First => 0,
34 Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
35 Navigation::Previous => *offset - limit,
36 Navigation::Next => *offset + limit,
37 Navigation::Page(n) => n * limit,
38 };
39
40 onoffset.emit(offset);
41 },
42 );
43
44 let set_display_cards = use_callback(display_cards.setter(), |value, display_cards_setter| {
45 display_cards_setter.set(value);
46 });
47
48 let items_render = if *display_cards {
49 html!(
50 <ListAssetsGallery
51 asset_items={props.asset_items.clone()}
52 onshow={props.onshow.clone()}
53 button_label={props.button_label.clone()}
54 />
55 )
56 } else {
57 html!(
58 <ListAssetsTable
59 asset_items={props.asset_items.clone()}
60 onshow={props.onshow.clone()}
61 button_label={props.button_label.clone()}
62 />
63 )
64 };
65
66 html!(
67 <>
68 <Toolbar>
69 <ToolbarContent>
70 <ToolbarItem>
71 <Button
72 variant={ButtonVariant::Tertiary}
73 icon={Icon::ThLarge}
74 disabled={*display_cards}
75 onclick={set_display_cards.reform(|_| true)}
76 />
77 <Button
78 variant={ButtonVariant::Tertiary}
79 icon={Icon::List}
80 disabled={!*display_cards}
81 onclick={set_display_cards.reform(|_| false)}
82 />
83 </ToolbarItem>
84 <ToolbarItem r#type={ToolbarItemType::Pagination}>
85 <Pagination
86 offset={props.offset}
87 entries_per_page_choices={vec![5, 10, 25, 50, 100]}
88 selected_choice={props.limit}
89 onlimit={&props.onlimit}
90 onnavigation={&nav_callback}
91 />
92 </ToolbarItem>
93 </ToolbarContent>
94 </Toolbar>
95 { items_render }
96 </>
97 )
98}
99
100#[derive(Clone, Debug, PartialEq, Properties)]
101pub struct ListAssetsTableProps {
102 pub asset_items: Vec<AssetItem>,
103 pub onshow: Callback<String>,
104 #[prop_or(AttrValue::Static("Select"))]
105 pub button_label: AttrValue,
106}
107
108#[component]
109pub fn ListAssetsGallery(props: &ListAssetsTableProps) -> Html {
110 let rows = props
111 .asset_items
112 .clone()
113 .into_iter()
114 .map(DataspaceDataset::from)
115 .map(|dataset| {
116 let asset_id = dataset.id.clone();
117
118 html!(
119 <DatasetCard
120 {dataset}
121 on_offer_click={props.onshow.reform(move |_| asset_id.clone())}
122 button_label={props.button_label.clone()}
123 />
124 )
125 });
126
127 html!(<Gallery gutter=true>{ for rows }</Gallery>)
128}
129
130#[component]
131pub fn ListAssetsTable(props: &ListAssetsTableProps) -> Html {
132 let header = html_nested! {
133 <TableHeader<Columns>>
134 <TableColumn<Columns> label="Name" index={Columns::Name} />
135 <TableColumn<Columns> label="Base URL" index={Columns::BaseUrl} />
136 <TableColumn<Columns> label="Proxy Path" index={Columns::ProxyPath} />
137 <TableColumn<Columns> label="Proxy Query Parameters" index={Columns::ProxyQueryParameters} />
138 <TableColumn<Columns> label="Proxy Method" index={Columns::ProxyMethod} />
139 <TableColumn<Columns> label="Proxy Body" index={Columns::ProxyBody} />
140 <TableColumn<Columns> label="" index={Columns::Actions} />
141 </TableHeader<Columns>>
142 };
143
144 let rows = props
145 .asset_items
146 .iter()
147 .map(|asset_item| AssetRenderer {
148 asset_item: asset_item.clone(),
149 onshow: props.onshow.clone(),
150 })
151 .collect();
152
153 let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
154
155 html!(
156 <Table<Columns, UseTableData<Columns, MemoizedTableModel<AssetRenderer>>>
157 mode={TableMode::Compact}
158 {header}
159 {entries}
160 />
161 )
162}
163
164#[derive(Clone, Debug, Eq, PartialEq)]
165enum Columns {
166 Name,
167 BaseUrl,
168 ProxyPath,
169 ProxyQueryParameters,
170 ProxyMethod,
171 ProxyBody,
172 Actions,
173}
174
175#[derive(Clone, Debug)]
176struct AssetRenderer {
177 asset_item: AssetItem,
178 onshow: Callback<String>,
179}
180
181impl TableEntryRenderer<Columns> for AssetRenderer {
182 fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
183 match context.column {
184 Columns::Name => html!(self.asset_item.name.to_owned()),
185 Columns::BaseUrl => html!(self.asset_item.base_url.to_owned()),
186 Columns::ProxyPath => html!(self.asset_item.proxy_path),
187 Columns::ProxyQueryParameters => html!(self.asset_item.proxy_query_params),
188 Columns::ProxyMethod => html!(self.asset_item.proxy_method),
189 Columns::ProxyBody => html!(self.asset_item.proxy_body),
190 Columns::Actions => {
191 let asset_id = self.asset_item.id.to_string();
192
193 html!(<ShowAsset {asset_id} onshow={self.onshow.clone()} />)
194 }
195 }
196 .into()
197 }
198}
199
200#[derive(Clone, PartialEq, Properties)]
201pub struct ShowAssetProps {
202 pub asset_id: String,
203 pub onshow: Callback<String>,
204}
205
206#[function_component]
207pub fn ShowAsset(props: &ShowAssetProps) -> Html {
208 let onclick = use_callback(
209 (props.asset_id.clone(), props.onshow.clone()),
210 |_, (asset_id, onshow)| {
211 onshow.emit(asset_id.to_string());
212 },
213 );
214
215 html!(<Button variant={ButtonVariant::Primary} icon={Icon::Eye} {onclick}>{ "Show" }</Button>)
216}