edc_web_components/pages/
federated_catalog_page.rs1use crate::components::{ListAssetsGallery, SelectedFederatedCatalogOffer};
2use crate::models::{AssetItem, Creator, Thumbnail};
3use edc_federated_catalog_client::{FederatedCatalogClient, FederatedCatalogClientVersion};
4use patternfly_yew::prelude::*;
5use yew::prelude::*;
6use yew::suspense::use_future_with;
7use yew_oauth2::hook::use_latest_access_token;
8
9#[derive(Clone, Debug, PartialEq, Properties)]
10pub struct CatalogPageProps {
11 pub onselectedoffer: Callback<SelectedFederatedCatalogOffer>,
12}
13
14#[component]
15pub fn CatalogPage(props: &CatalogPageProps) -> Html {
16 let refresh = use_state(|| 0usize);
17
18 html!(
19 <Stack gutter=true>
20 <StackItem>
21 <Split gutter=true>
22 <SplitItem fill=true>
23 <Title level={Level::H3} size={Size::XXLarge}>{ "Catalog" }</Title>
24 </SplitItem>
25 </Split>
26 </StackItem>
27 <StackItem>
28 <Suspense>
29 <CatalogPageInner
30 force_refresh={*refresh}
31 onselectedoffer={props.onselectedoffer.clone()}
32 />
33 </Suspense>
34 </StackItem>
35 </Stack>
36 )
37}
38
39#[derive(Clone, Debug, PartialEq, Properties)]
40pub struct CatalogPageInnerProps {
41 pub force_refresh: usize,
42 pub onselectedoffer: Callback<SelectedFederatedCatalogOffer>,
43}
44
45#[component]
46pub fn CatalogPageInner(props: &CatalogPageInnerProps) -> HtmlResult {
47 let latest_access_token_context = use_latest_access_token().unwrap();
48
49 let asset_items = use_future_with(
50 (latest_access_token_context.clone(), props.force_refresh),
51 |parameters| async move {
52 let (latest_access_token_context, _) = (*parameters).clone();
53
54 let server_url = web_sys::window().unwrap().location().origin().unwrap();
55 let federated_catalog_client = FederatedCatalogClient::new(
56 reqwest::Client::new(),
57 format!("{server_url}/federated-catalog"),
58 latest_access_token_context.access_token(),
59 FederatedCatalogClientVersion::V4,
60 );
61
62 federated_catalog_client
63 .list_offers()
64 .await
65 .unwrap_or_default()
66 .iter()
67 .flat_map(|federated_catalog_offer| {
68 federated_catalog_offer
69 .dataset
70 .clone()
71 .into_iter()
72 .map(|dataset| {
73 let asset_item = AssetItem {
74 id: dataset.id.clone(),
75 name: dataset.name,
76 version: dataset
77 .version
78 .and_then(|version| semver::Version::parse(&version).ok()),
79 description: dataset.description,
80 creator: dataset.creator.map(|creator| Creator {
81 name: Some(creator.name),
82 thumbnail: Some(Thumbnail {
83 resource: Some(creator.thumbnail.resource),
84 }),
85 }),
86 thumbnail: dataset.thumbnail.map(|thumbnail| Thumbnail {
87 resource: Some(thumbnail.resource),
88 }),
89 keywords: dataset.keywords,
90 base_url: "".to_string(),
91 proxy_path: false,
92 proxy_query_params: false,
93 proxy_method: false,
94 proxy_body: false,
95 };
96
97 let selected_offer = SelectedFederatedCatalogOffer {
98 originator: federated_catalog_offer.originator.clone(),
99 provider_id: federated_catalog_offer.participant_id.id.clone(),
100 dataset_id: dataset.id.clone(),
101 };
102
103 (asset_item, selected_offer)
104 })
105 .collect::<Vec<_>>()
106 })
107 .unzip()
108 },
109 )?;
110
111 let (asset_items, selected_offers): (Vec<AssetItem>, Vec<SelectedFederatedCatalogOffer>) =
112 (*asset_items).clone();
113
114 let onshow = use_callback(
115 (props.onselectedoffer.clone(), selected_offers),
116 |dataset_id, (onselectedoffer, selected_offers)| {
117 if let Some(selected_offer) = selected_offers
118 .iter()
119 .find(|selected_offer| selected_offer.dataset_id == dataset_id)
120 {
121 onselectedoffer.emit(selected_offer.clone());
122 }
123 },
124 );
125
126 Ok(html!(<ListAssetsGallery {asset_items} {onshow} />))
127}