Skip to main content

edc_web_components/components/
create_federated_catalog_participant.rs

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