Skip to main content

edc_web_components/contexts/
edc_federated_catalog_assets_context.rs

1use crate::components::SelectedFederatedCatalogOffer;
2use crate::models::AssetItem;
3use edc_federated_catalog_client::{FederatedCatalogClient, FederatedCatalogClientVersion};
4use std::{ops::Deref, rc::Rc};
5use yew::prelude::*;
6use yew::suspense::use_future_with;
7use yew_oauth2::hook::use_latest_access_token;
8
9#[derive(Debug, PartialEq, Clone)]
10pub enum EdcFederatedCatalogAssetsAction {
11  SetAssetsAndSelectedOffers(Vec<(AssetItem, SelectedFederatedCatalogOffer)>),
12}
13
14#[derive(Clone, PartialEq)]
15pub struct EdcFederatedCatalogAssetsContextState {
16  asset_items: Vec<AssetItem>,
17  selected_offers: Vec<SelectedFederatedCatalogOffer>,
18}
19
20impl EdcFederatedCatalogAssetsContextState {
21  pub fn asset(&self, asset_id: &str) -> Option<&AssetItem> {
22    self
23      .asset_items
24      .iter()
25      .find(|asset_item| asset_item.id == asset_id)
26  }
27
28  pub fn asset_items(&self) -> &[AssetItem] {
29    &self.asset_items
30  }
31
32  pub fn selected_offers(&self) -> &[SelectedFederatedCatalogOffer] {
33    &self.selected_offers
34  }
35}
36
37impl Reducible for EdcFederatedCatalogAssetsContextState {
38  type Action = EdcFederatedCatalogAssetsAction;
39
40  fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
41    let mut new_self = self.deref().clone();
42
43    let EdcFederatedCatalogAssetsAction::SetAssetsAndSelectedOffers(assets_and_selected_offers) =
44      action;
45
46    let (assets, selected_offers) = assets_and_selected_offers.into_iter().unzip();
47
48    new_self.asset_items = assets;
49    new_self.selected_offers = selected_offers;
50
51    new_self.into()
52  }
53}
54
55#[derive(Properties, PartialEq)]
56pub struct EdcFederatedCatalogAssetsContextProviderProps {
57  #[prop_or_default]
58  pub children: Html,
59}
60
61#[component]
62pub fn EdcFederatedCatalogAssetsContextProvider(
63  props: &EdcFederatedCatalogAssetsContextProviderProps,
64) -> Html {
65  let did_resolver_context = use_reducer(move || EdcFederatedCatalogAssetsContextState {
66    asset_items: vec![],
67    selected_offers: vec![],
68  });
69
70  html! {
71    <ContextProvider<EdcFederatedCatalogAssetsContext> context={did_resolver_context}>
72      { props.children.clone() }
73    </ContextProvider<EdcFederatedCatalogAssetsContext >>
74  }
75}
76
77pub type EdcFederatedCatalogAssetsContext = UseReducerHandle<EdcFederatedCatalogAssetsContextState>;
78
79#[hook]
80pub fn use_edc_federated_catalog_assets_context() -> Option<EdcFederatedCatalogAssetsContext> {
81  use_context::<EdcFederatedCatalogAssetsContext>()
82}
83
84#[derive(Properties, PartialEq)]
85pub struct EdcFederatedCatalogAssetsFetcherProps {
86  #[prop_or("/federated-catalog".to_string())]
87  pub federated_catalog_endpoint: String,
88  #[prop_or_default]
89  pub search: Option<String>,
90  #[prop_or_default]
91  pub dcterm_types: Vec<String>,
92  #[prop_or_default]
93  pub force_refresh: usize,
94}
95
96#[component]
97pub fn EdcFederatedCatalogAssetsFetcher(
98  props: &EdcFederatedCatalogAssetsFetcherProps,
99) -> HtmlResult {
100  let latest_access_token_context = use_latest_access_token().unwrap();
101  let edc_federated_catalog_assets_context = use_edc_federated_catalog_assets_context();
102
103  let _ = use_future_with(
104    (
105      props.force_refresh,
106      props.federated_catalog_endpoint.clone(),
107      props.search.clone(),
108      props.dcterm_types.clone(),
109      latest_access_token_context.clone(),
110      edc_federated_catalog_assets_context.clone(),
111    ),
112    |parameters| async move {
113      let (
114        _,
115        federated_catalog_endpoint,
116        search,
117        dcterm_types,
118        latest_access_token_context,
119        edc_federated_catalog_assets_context,
120      ) = (*parameters).clone();
121
122      if let Some(edc_federated_catalog_assets_context) = edc_federated_catalog_assets_context {
123        let server_url = web_sys::window().unwrap().location().origin().unwrap();
124        let federated_catalog_client = FederatedCatalogClient::new(
125          reqwest::Client::new(),
126          format!("{server_url}{}", federated_catalog_endpoint),
127          latest_access_token_context.access_token(),
128          FederatedCatalogClientVersion::V4,
129        );
130
131        let assets_and_selected_offers = federated_catalog_client
132          .list_offers()
133          .await
134          .unwrap_or_default()
135          .iter()
136          .flat_map(|federated_catalog_offer| {
137            federated_catalog_offer
138              .dataset
139              .clone()
140              .into_iter()
141              .map(|dataset| {
142                let dataset_id = dataset.id.clone();
143                let asset_item = AssetItem::from(dataset);
144
145                let selected_offer = SelectedFederatedCatalogOffer {
146                  originator: federated_catalog_offer.originator.clone(),
147                  provider_id: federated_catalog_offer.participant_id.id.clone(),
148                  dataset_id,
149                };
150
151                (asset_item, selected_offer)
152              })
153              .filter(|(asset_item, _)| asset_item.is_filtered(&search, &dcterm_types))
154              .collect::<Vec<_>>()
155          })
156          .collect::<Vec<_>>();
157
158        edc_federated_catalog_assets_context.dispatch(
159          EdcFederatedCatalogAssetsAction::SetAssetsAndSelectedOffers(assets_and_selected_offers),
160        );
161      }
162    },
163  )?;
164
165  Ok(html!())
166}