Skip to main content

edc_web_components/components/
asset_selector.rs

1use crate::components::DatasetCard;
2use crate::contexts::use_edc_connector_context;
3use crate::models::{AssetItem, DataspaceDataset};
4use edc_connector_client::EdcConnectorApiVersion;
5use edc_connector_client::types::query::Query;
6use patternfly_yew::prelude::*;
7use yew::prelude::*;
8use yew::suspense::use_future_with;
9
10#[derive(Clone, Debug, PartialEq, Properties)]
11pub struct AssetSelectorProps {
12  pub selected_assets: Vec<AssetItem>,
13  pub onselect: Callback<Vec<AssetItem>>,
14  #[prop_or("selectable-asset".to_string())]
15  pub select_id: String,
16}
17
18#[component]
19pub fn AssetSelector(props: &AssetSelectorProps) -> Html {
20  html!(
21    <Suspense>
22      <AssetSelectorInner
23        onselect={props.onselect.clone()}
24        selected_assets={props.selected_assets.clone()}
25        select_id={props.select_id.clone()}
26      />
27    </Suspense>
28  )
29}
30
31#[derive(Clone, Debug, PartialEq, Properties)]
32pub struct AssetSelectorInnerProps {
33  pub selected_assets: Vec<AssetItem>,
34  pub onselect: Callback<Vec<AssetItem>>,
35  pub select_id: String,
36}
37
38#[component]
39fn AssetSelectorInner(props: &AssetSelectorInnerProps) -> HtmlResult {
40  let limit = use_state(|| 10usize);
41  let offset = use_state(|| 0usize);
42  let force_refresh = use_state(|| 0usize);
43  let edc_connector_context = use_edc_connector_context();
44
45  let assets = use_future_with(
46    (edc_connector_context, *limit, *offset, *force_refresh),
47    |parameters| async move {
48      let (edc_connector_context, limit, offset, _) = (*parameters).clone();
49
50      let query = Query::builder()
51        .limit(limit as u32)
52        .offset(offset as u32)
53        .build();
54
55      if let Some(client) = edc_connector_context.get_client() {
56        client
57          .assets(EdcConnectorApiVersion::V4)
58          .query(query)
59          .await
60          .unwrap_or_default()
61          .into_iter()
62          .map(AssetItem::from)
63          .collect::<Vec<_>>()
64      } else {
65        vec![]
66      }
67    },
68  )?;
69
70  let assets = (*assets).clone();
71
72  let on_selected = use_callback(
73    (props.selected_assets.clone(), props.onselect.clone()),
74    |(asset_id, selected), (selected_assets, onselect)| {
75      let mut selected_assets = selected_assets.clone();
76
77      if selected {
78        selected_assets.push(asset_id);
79      } else {
80        selected_assets.retain(|id| id != &asset_id);
81      }
82
83      onselect.emit(selected_assets);
84    },
85  );
86
87  let items = assets.iter().map(|asset_item| {
88    let selected = props.selected_assets.contains(asset_item);
89    let dataset = DataspaceDataset::from(asset_item.clone());
90    let asset_item = asset_item.clone();
91
92    html!(
93      <DatasetCard
94        {dataset}
95        {selected}
96        on_selected={on_selected.reform(move |selected| (asset_item.clone(), selected) )}
97      />
98    )
99  });
100
101  let onlimit = use_callback(limit.setter(), |limit, limit_setter| {
102    limit_setter.set(limit)
103  });
104
105  let total_entries = Option::<usize>::None;
106
107  let nav_callback = use_callback(
108    (offset.clone(), *limit, total_entries),
109    |page: Navigation, (offset, limit, total_entries)| {
110      let new_offset = match page {
111        Navigation::First => 0,
112        Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
113        Navigation::Previous => **offset - limit,
114        Navigation::Next => **offset + limit,
115        Navigation::Page(n) => n * limit,
116      };
117      offset.set(new_offset);
118    },
119  );
120
121  Ok(html!(
122    <Stack gutter=true>
123      <StackItem>
124        <Pagination
125          offset={*offset}
126          entries_per_page_choices={vec![5, 10, 25, 50, 100]}
127          selected_choice={*limit}
128          onlimit={&onlimit}
129          onnavigation={&nav_callback}
130        />
131      </StackItem>
132      <StackItem>
133        <Gallery gutter=true>{ for items }</Gallery>
134      </StackItem>
135    </Stack>
136  ))
137}