Skip to main content

edc_web_components/components/
transfer_process_status.rs

1use crate::contexts::use_edc_connector_context;
2use edc_connector_client::types::transfer_process::{TransferProcess, TransferProcessState};
3use patternfly_yew::prelude::*;
4use std::time::Duration;
5use yew::platform::spawn_local;
6use yew::platform::time::sleep;
7use yew::prelude::*;
8
9const HAPPY_PATH_STATES: [(&str, TransferProcessState); 5] = [
10  ("Initial", TransferProcessState::Initial),
11  ("Provisioned", TransferProcessState::Provisioned),
12  ("Requested", TransferProcessState::Requested),
13  ("Started", TransferProcessState::Started),
14  ("Completed", TransferProcessState::Completed),
15];
16
17#[derive(Clone, Debug, PartialEq, Properties)]
18pub struct TransferProcessStatusProps {
19  pub transfer_process_id: String,
20  #[prop_or_default]
21  pub on_started: Callback<()>,
22  #[prop_or_default]
23  pub on_finalized: Callback<()>,
24}
25
26#[component]
27pub fn TransferProcessStatus(props: &TransferProcessStatusProps) -> Html {
28  let edc_connector_client = use_edc_connector_context();
29
30  let transfer_process_state = use_state(|| None);
31  let transfer_process_message = use_state(|| Option::<String>::None);
32
33  use_effect_with(
34    (
35      props.transfer_process_id.clone(),
36      edc_connector_client.clone(),
37      transfer_process_state.setter(),
38      transfer_process_message.setter(),
39      props.on_finalized.clone(),
40      props.on_started.clone(),
41    ),
42    |(
43      transfer_process_id,
44      edc_connector_client,
45      transfer_process_state_setter,
46      transfer_process_message_setter,
47      on_finalized,
48      on_started,
49    )| {
50      let transfer_process_id = transfer_process_id.clone();
51      let edc_connector_client = edc_connector_client.clone();
52      let transfer_process_state_setter = transfer_process_state_setter.clone();
53      let transfer_process_message_setter = transfer_process_message_setter.clone();
54      let on_finalized = on_finalized.clone();
55      let on_started = on_started.clone();
56
57      spawn_local(async move {
58        loop {
59          let transfer_process = if let Some(client) = edc_connector_client.get_client() {
60            client
61              .transfer_processes(edc_connector_client::EdcConnectorApiVersion::V4)
62              .get(&transfer_process_id)
63              .await
64              .ok()
65          } else {
66            None
67          };
68
69          let state = transfer_process
70            .as_ref()
71            .map(|transfer_process| transfer_process.state().clone());
72
73          let error_message = transfer_process.as_ref().and_then(|transfer_process| {
74            transfer_process
75              .error_detail()
76              .map(|error_detail| error_detail.to_string())
77          });
78
79          transfer_process_message_setter.set(error_message);
80
81          transfer_process_state_setter.set(transfer_process);
82
83          if state == Some(TransferProcessState::Started) {
84            on_started.emit(());
85            break;
86          }
87
88          if state == Some(TransferProcessState::Completed)
89            || state == Some(TransferProcessState::Terminated)
90            || state == Some(TransferProcessState::Suspended)
91          {
92            on_finalized.emit(());
93            break;
94          }
95
96          sleep(Duration::from_secs(1)).await;
97        }
98      });
99    },
100  );
101
102  match (
103    (*transfer_process_message).clone(),
104    (*transfer_process_state).clone(),
105  ) {
106    (Some(message), Some(transfer_process)) => {
107      let (title, r#type) = if transfer_process.state() == &TransferProcessState::Terminated {
108        ("Transfer Process failed", AlertType::Danger)
109      } else {
110        ("Transfer Process suspended", AlertType::Warning)
111      };
112
113      html!(
114        <Alert {title} {r#type}>
115          <div>{ message }</div>
116        </Alert>
117      )
118    }
119    (None, Some(transfer_process)) => {
120      let transfer_process: TransferProcess = transfer_process;
121
122      let current_state_index = HAPPY_PATH_STATES
123        .iter()
124        .position(|(_, state)| state == transfer_process.state())
125        .unwrap_or_default();
126
127      let steps = HAPPY_PATH_STATES
128        .iter()
129        .enumerate()
130        .map(|(index, (state_label, _))| {
131          let status = if index < current_state_index {
132            ProgressStepperStepStatus::Success
133          } else if index == current_state_index {
134            if index == HAPPY_PATH_STATES.len() - 1 {
135              ProgressStepperStepStatus::Success
136            } else {
137              ProgressStepperStepStatus::Default
138            }
139          } else {
140            ProgressStepperStepStatus::Pending
141          };
142
143          html_nested!(
144            <ProgressStepperStep {status}>
145              <div>{ state_label.to_string() }</div>
146            </ProgressStepperStep>
147          )
148        });
149
150      html!(<ProgressStepper>{ for steps }</ProgressStepper>)
151    }
152    _ => html!(),
153  }
154}