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