edc_web_components/pages/
contract_negotiation_page.rs1use 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}