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