Skip to main content

edc_web_components/pages/
contract_negotiation_page.rs

1use crate::components::ListContractNegotiations;
2use crate::contexts::use_edc_connector_context;
3use crate::models::{ConsumerProvider, ContractNegotiationItem};
4use edc_connector_client::EdcConnectorApiVersion;
5use edc_connector_client::types::query::{Query, SortOrder};
6use patternfly_yew::prelude::*;
7use std::collections::HashSet;
8use yew::prelude::*;
9use yew::suspense::use_future_with;
10
11#[derive(Clone, Debug, PartialEq, Properties)]
12pub struct ContractNegotiationPageProps {
13  pub on_show_contract_negotiation: Callback<String>,
14}
15
16#[component]
17pub fn ContractNegotiationPage(props: &ContractNegotiationPageProps) -> Html {
18  let refresh = use_state(|| 0usize);
19  let offset = use_state(|| 0usize);
20  let limit = use_state(|| 10usize);
21  let consumer_provider = use_state(HashSet::default);
22  let statuses = use_state(|| {
23    vec![
24      ("Initial".to_string(), false),
25      ("Requesting".to_string(), false),
26      ("Requested".to_string(), false),
27      ("Offering".to_string(), false),
28      ("Offered".to_string(), false),
29      ("Accepting".to_string(), false),
30      ("Accepted".to_string(), false),
31      ("Agreeing".to_string(), false),
32      ("Agreed".to_string(), false),
33      ("Verifying".to_string(), false),
34      ("Verified".to_string(), false),
35      ("Finalizing".to_string(), false),
36      ("Finalized".to_string(), false),
37      ("Terminating".to_string(), false),
38      ("Terminated".to_string(), false),
39    ]
40  });
41
42  let on_offset = use_callback(
43    (refresh.clone(), offset.setter()),
44    |offset, (refresh, offset_setter)| {
45      offset_setter.set(offset);
46      refresh.set(**refresh + 1);
47    },
48  );
49
50  let on_limit = use_callback(
51    (refresh.clone(), limit.setter()),
52    |limit, (refresh, limit_setter)| {
53      limit_setter.set(limit);
54      refresh.set(**refresh + 1);
55    },
56  );
57
58  let on_consumer_provider = use_callback(
59    (refresh.clone(), consumer_provider.setter()),
60    |consumer_provider, (refresh, consumer_provider_setter)| {
61      consumer_provider_setter.set(consumer_provider);
62      refresh.set(**refresh + 1);
63    },
64  );
65
66  let on_statuses = use_callback(
67    (refresh.clone(), statuses.setter()),
68    |statuses, (refresh, statuses_setter)| {
69      statuses_setter.set(statuses);
70      refresh.set(**refresh + 1);
71    },
72  );
73
74  let fallback = html! {
75    <Bullseye>
76      <Spinner size={SpinnerSize::Lg} />
77    </Bullseye>
78  };
79
80  html!(
81    <Stack gutter=true>
82      <StackItem>
83        <Split gutter=true>
84          <SplitItem fill=true>
85            <Title level={Level::H3} size={Size::XXLarge}>{ "List Contract Negotiations" }</Title>
86            <p>
87              { "A contract negotiation represents the active, multi-step process between two parties to agree on data sharing terms." }
88            </p>
89          </SplitItem>
90        </Split>
91      </StackItem>
92      <StackItem>
93        <Suspense {fallback}>
94          <ContractNegotiationPageInner
95            offset={*offset}
96            limit={*limit}
97            statuses={(*statuses).clone()}
98            {on_offset}
99            {on_limit}
100            {on_statuses}
101            force_refresh={*refresh}
102            on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
103            consumer_provider={(*consumer_provider).clone()}
104            {on_consumer_provider}
105          />
106        </Suspense>
107      </StackItem>
108    </Stack>
109  )
110}
111
112#[derive(Clone, Debug, PartialEq, Properties)]
113pub struct ContractNegotiationPageInnerProps {
114  pub offset: usize,
115  pub limit: usize,
116  #[prop_or_default]
117  pub statuses: Vec<(String, bool)>,
118  pub on_offset: Callback<usize>,
119  pub on_limit: Callback<usize>,
120  pub on_statuses: Callback<Vec<(String, bool)>>,
121  pub force_refresh: usize,
122  pub on_show_contract_negotiation: Callback<String>,
123  #[prop_or(true)]
124  pub show_status_selector: bool,
125  #[prop_or_default]
126  pub consumer_provider: HashSet<ConsumerProvider>,
127  pub on_consumer_provider: Callback<HashSet<ConsumerProvider>>,
128}
129
130#[component]
131pub fn ContractNegotiationPageInner(props: &ContractNegotiationPageInnerProps) -> HtmlResult {
132  let edc_connector_context = use_edc_connector_context();
133
134  let contract_negotiation_items = use_future_with(
135    (
136      edc_connector_context,
137      props.limit,
138      props.offset,
139      props.consumer_provider.clone(),
140      props.statuses.clone(),
141      props.force_refresh,
142    ),
143    |parameters| async move {
144      let (edc_connector_context, limit, offset, consumer_provider, statuses, _) =
145        (*parameters).clone();
146
147      let query_builder = Query::builder().limit(limit as u32).offset(offset as u32);
148
149      let query_builder = match (
150        consumer_provider.contains(&ConsumerProvider::Consumer),
151        consumer_provider.contains(&ConsumerProvider::Provider),
152      ) {
153        (true, true) => query_builder,
154        (true, false) => query_builder.filter("type", "=", "CONSUMER"),
155        (false, true) => query_builder.filter("type", "=", "PROVIDER"),
156        (false, false) => query_builder,
157      };
158
159      let query_builder = if statuses.iter().all(|(_, selected)| *selected)
160        || statuses.iter().all(|(_, selected)| !*selected)
161      {
162        query_builder
163      } else {
164        let list = statuses
165          .iter()
166          .filter_map(|(label, selected)| {
167            if *selected {
168              Some(label.clone().to_uppercase())
169            } else {
170              None
171            }
172          })
173          .collect::<Vec<_>>();
174
175        query_builder.filter("state", "IN", list)
176      };
177
178      let query = query_builder.sort("createdAt", SortOrder::Desc).build();
179
180      if let Some(client) = edc_connector_context.get_client() {
181        client
182          .contract_negotiations(EdcConnectorApiVersion::V4)
183          .query(query)
184          .await
185          .unwrap_or_default()
186          .into_iter()
187          .map(ContractNegotiationItem::from)
188          .collect()
189      } else {
190        vec![]
191      }
192    },
193  )?;
194
195  let contract_negotiation_items = (*contract_negotiation_items).clone();
196
197  Ok(html!(
198    <ListContractNegotiations
199      contract_negotiation_items={contract_negotiation_items}
200      offset={props.offset}
201      limit={props.limit}
202      statuses={props.statuses.clone()}
203      on_offset={props.on_offset.clone()}
204      on_limit={props.on_limit.clone()}
205      on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
206      on_statuses={props.on_statuses.clone()}
207      show_status_selector={props.show_status_selector}
208      consumer_provider={props.consumer_provider.clone()}
209      on_consumer_provider={props.on_consumer_provider.clone()}
210    />
211  ))
212}