Skip to main content

edc_web_components/components/
list_assets.rs

1use 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}