edc_web_components/components/
create_federated_catalog_participant.rs1use crate::contexts::{CounterParty, use_counter_parties_context};
2use crate::services::get_dsp_endpoint;
3use edc_federated_catalog_client::models::FederatedCatalogParticipantCreateForm;
4use edc_federated_catalog_client::{FederatedCatalogClient, FederatedCatalogClientVersion};
5use edc_identity_hub_client::models::DidWeb;
6use patternfly_yew::prelude::*;
7use yew::platform::spawn_local;
8use yew::prelude::*;
9use yew_oauth2::hook::use_latest_access_token;
10
11#[derive(Clone, Debug, PartialEq, Properties)]
12pub struct CreateFederatedCatalogParticipantProps {
13 #[prop_or_default]
14 pub on_create: Callback<()>,
15}
16
17#[component]
18pub fn CreateFederatedCatalogParticipant(props: &CreateFederatedCatalogParticipantProps) -> Html {
19 let counter_parties_context = use_counter_parties_context();
20
21 let id = use_state(|| "".to_string());
22 let target_url = use_state(|| "".to_string());
23
24 let onchange_id = use_callback(
25 (id.setter(), target_url.setter()),
26 |did: String, (id_setter, target_url_setter)| {
27 let target_setter = target_url_setter.clone();
28
29 if let Some(did_web) = DidWeb::new(&did) {
30 spawn_local(async move {
31 if let Some(dsp_endpoint) = get_dsp_endpoint(&did_web).await {
32 target_setter.set(dsp_endpoint);
33 }
34 });
35 }
36
37 id_setter.set(did);
38 },
39 );
40
41 let onchange_target_url = use_callback(target_url.setter(), |value, target_url_setter| {
42 target_url_setter.set(value);
43 });
44
45 let disabled = false;
46
47 let latest_access_token_context = use_latest_access_token().unwrap();
48
49 let onsubmit = use_callback(
50 (
51 id.clone(),
52 target_url.clone(),
53 props.on_create.clone(),
54 latest_access_token_context.clone(),
55 ),
56 |event: SubmitEvent, (id, target_url, on_create, latest_access_token_context)| {
57 event.prevent_default();
58 let on_create = on_create.clone();
59 let latest_access_token_context = latest_access_token_context.clone();
60
61 let id = (**id).clone();
62 let target_url = (**target_url).clone();
63
64 spawn_local(async move {
65 let server_url = web_sys::window().unwrap().location().origin().unwrap();
66 let federated_catalog_management_client = FederatedCatalogClient::new(
67 reqwest::Client::new(),
68 format!("{server_url}/federated-catalog-management"),
69 latest_access_token_context.access_token(),
70 FederatedCatalogClientVersion::V4,
71 );
72
73 match federated_catalog_management_client
74 .create_participant(&FederatedCatalogParticipantCreateForm {
75 id: id.clone(),
76 name: "".to_string(),
77 target_url: target_url.clone(),
78 })
79 .await
80 {
81 Ok(()) => {
82 on_create.emit(());
83 }
84 Err(message) => {
85 log::error!("{message}");
86 }
87 }
88 })
89 },
90 );
91
92 let form = html!(
93 <Form {onsubmit}>
94 <FormGroup label="Counter Party DID" required=true>
95 <TextInput required=true value={(*id).to_string()} onchange={onchange_id} />
96 </FormGroup>
97 <FormGroup label="Counter Party Address" required=true>
98 <TextInput
99 required=true
100 value={(*target_url).to_string()}
101 onchange={onchange_target_url}
102 r#type={TextInputType::Url}
103 />
104 </FormGroup>
105 <ActionGroup>
106 <Button
107 variant={ButtonVariant::Primary}
108 label="Submit"
109 r#type={ButtonType::Submit}
110 {disabled}
111 />
112 <Button variant={ButtonVariant::Secondary} label="Reset" r#type={ButtonType::Reset} />
113 </ActionGroup>
114 </Form>
115 );
116
117 let selected = use_state_eq(|| TabIndex::CounterPartySelect);
118 let onselect = use_callback(selected.clone(), |index, selected| selected.set(index));
119
120 let toaster = use_toaster();
121
122 let select_counter_party = use_callback(
123 (
124 props.on_create.clone(),
125 latest_access_token_context.clone(),
126 toaster.clone(),
127 ),
128 |counter_party: CounterParty, (on_create, latest_access_token_context, toaster)| {
129 let on_create = on_create.clone();
130 let latest_access_token_context = latest_access_token_context.clone();
131 let counter_party = counter_party.clone();
132 let toaster = toaster.clone();
133
134 spawn_local(async move {
135 if let Some(did_web) = DidWeb::new(&counter_party.did) {
136 if let Some(dsp_endpoint) = get_dsp_endpoint(&did_web).await {
137 let server_url = web_sys::window().unwrap().location().origin().unwrap();
138 let federated_catalog_management_client = FederatedCatalogClient::new(
139 reqwest::Client::new(),
140 format!("{server_url}/federated-catalog-management"),
141 latest_access_token_context.access_token(),
142 FederatedCatalogClientVersion::V4,
143 );
144
145 match federated_catalog_management_client
146 .create_participant(&FederatedCatalogParticipantCreateForm {
147 id: counter_party.did.clone(),
148 name: counter_party.name.to_string(),
149 target_url: dsp_endpoint.clone(),
150 })
151 .await
152 {
153 Ok(()) => {
154 on_create.emit(());
155 }
156 Err(message) => {
157 log::error!("{message}");
158 if let Some(toaster) = toaster {
159 toaster.toast(Toast {
160 title: "Unable to create federated catalog participant".to_string(),
161 body: html! { <p>{ message.to_string() }</p> },
162 r#type: AlertType::Warning,
163 ..Default::default()
164 });
165 }
166 }
167 }
168 } else {
169 if let Some(toaster) = toaster {
170 toaster.toast(Toast {
171 title: "Unable to create federated catalog participant".to_string(),
172 body: html! { <p>{ "No Dataspace Service available for this Participant" }</p> },
173 r#type: AlertType::Warning,
174 ..Default::default()
175 });
176 }
177 }
178 } else {
179 if let Some(toaster) = toaster {
180 toaster.toast(Toast {
181 title: "Unable to create federated catalog participant".to_string(),
182 body: html! { <p>{ "Incorrect Participant DID" }</p> },
183 r#type: AlertType::Warning,
184 ..Default::default()
185 });
186 }
187 }
188 })
189 },
190 );
191
192 if let Some(counter_parties_context) = counter_parties_context
193 && !counter_parties_context.counter_parties().is_empty()
194 {
195 let counter_parties = counter_parties_context
196 .counter_parties()
197 .iter()
198 .map(|counter_party| {
199 let onclick = {
200 let counter_party = counter_party.clone();
201
202 select_counter_party.reform(move |_| counter_party.clone())
203 };
204
205 html!(
206 <StackItem>
207 <Button variant={ButtonVariant::Secondary} {onclick}>{ &counter_party.name }</Button>
208 </StackItem>
209 )
210 });
211 html!(
212 <Tabs<TabIndex> {onselect} selected={*selected} r#box=true>
213 <Tab<TabIndex> index={TabIndex::CounterPartySelect} title="Select Counter Party">
214 <Panel>
215 <PanelMain>
216 <PanelMainBody>
217 <Stack gutter=true>{ for counter_parties }</Stack>
218 </PanelMainBody>
219 </PanelMain>
220 </Panel>
221 </Tab<TabIndex>>
222 <Tab<TabIndex> index={TabIndex::Form} title="Manual Entry">{ form }</Tab<TabIndex>>
223 </Tabs<TabIndex>>
224 )
225 } else {
226 form
227 }
228}
229
230#[derive(Clone, Copy, PartialEq, Eq)]
231enum TabIndex {
232 CounterPartySelect,
233 Form,
234}