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(|asset_item| DataspaceDataset {
115 id: asset_item.id,
116 title: asset_item.name,
117 version: asset_item.version,
118 comment: asset_item.description,
119 thumbnail: asset_item.thumbnail,
120 creator: asset_item.creator,
121 keywords: asset_item.keywords,
122 policies: vec![],
123 dcterm_types: vec![],
124 })
125 .map(|dataset| {
126 let asset_id = dataset.id.clone();
127
128 html!(
129 <DatasetCard
130 {dataset}
131 on_offer_click={props.onshow.reform(move |_| asset_id.clone())}
132 button_label={props.button_label.clone()}
133 />
134 )
135 });
136
137 html!(<Gallery gutter=true>{ for rows }</Gallery>)
138}
139
140#[component]
141pub fn ListAssetsTable(props: &ListAssetsTableProps) -> Html {
142 let header = html_nested! {
143 <TableHeader<Columns>>
144 <TableColumn<Columns> label="Name" index={Columns::Name} />
145 <TableColumn<Columns> label="Base URL" index={Columns::BaseUrl} />
146 <TableColumn<Columns> label="Proxy Path" index={Columns::ProxyPath} />
147 <TableColumn<Columns> label="Proxy Query Parameters" index={Columns::ProxyQueryParameters} />
148 <TableColumn<Columns> label="Proxy Method" index={Columns::ProxyMethod} />
149 <TableColumn<Columns> label="Proxy Body" index={Columns::ProxyBody} />
150 <TableColumn<Columns> label="" index={Columns::Actions} />
151 </TableHeader<Columns>>
152 };
153
154 let rows = props
155 .asset_items
156 .iter()
157 .map(|asset_item| AssetRenderer {
158 asset_item: asset_item.clone(),
159 onshow: props.onshow.clone(),
160 })
161 .collect();
162
163 let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
164
165 html!(
166 <Table<Columns, UseTableData<Columns, MemoizedTableModel<AssetRenderer>>>
167 mode={TableMode::Compact}
168 {header}
169 {entries}
170 />
171 )
172}
173
174#[derive(Clone, Debug, Eq, PartialEq)]
175enum Columns {
176 Name,
177 BaseUrl,
178 ProxyPath,
179 ProxyQueryParameters,
180 ProxyMethod,
181 ProxyBody,
182 Actions,
183}
184
185#[derive(Clone, Debug)]
186struct AssetRenderer {
187 asset_item: AssetItem,
188 onshow: Callback<String>,
189}
190
191impl TableEntryRenderer<Columns> for AssetRenderer {
192 fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
193 match context.column {
194 Columns::Name => html!(self.asset_item.name.to_owned()),
195 Columns::BaseUrl => html!(self.asset_item.base_url.to_owned()),
196 Columns::ProxyPath => html!(self.asset_item.proxy_path),
197 Columns::ProxyQueryParameters => html!(self.asset_item.proxy_query_params),
198 Columns::ProxyMethod => html!(self.asset_item.proxy_method),
199 Columns::ProxyBody => html!(self.asset_item.proxy_body),
200 Columns::Actions => {
201 let asset_id = self.asset_item.id.to_string();
202
203 html!(<ShowAsset {asset_id} onshow={self.onshow.clone()} />)
204 }
205 }
206 .into()
207 }
208}
209
210#[derive(Clone, PartialEq, Properties)]
211pub struct ShowAssetProps {
212 pub asset_id: String,
213 pub onshow: Callback<String>,
214}
215
216#[function_component]
217pub fn ShowAsset(props: &ShowAssetProps) -> Html {
218 let onclick = use_callback(
219 (props.asset_id.clone(), props.onshow.clone()),
220 |_, (asset_id, onshow)| {
221 onshow.emit(asset_id.to_string());
222 },
223 );
224
225 html!(<Button variant={ButtonVariant::Primary} icon={Icon::Eye} {onclick}>{ "Show" }</Button>)
226}