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 #[prop_or(true)]
125 pub show_status_selector: bool,
126 #[prop_or(true)]
127 pub show_consumer_provider_switch: bool,
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.switch_view_consumer,
140 props.statuses.clone(),
141 props.force_refresh,
142 ),
143 |parameters| async move {
144 let (edc_connector_context, limit, offset, switch_view_consumer, statuses, _) =
145 (*parameters).clone();
146
147 let query_builder = Query::builder()
148 .limit(limit as u32)
149 .offset(offset as u32)
150 .filter(
151 "type",
152 "=",
153 if switch_view_consumer {
154 "CONSUMER"
155 } else {
156 "PROVIDER"
157 },
158 );
159
160 let query_builder = if statuses.iter().all(|(_, selected)| *selected)
161 || statuses.iter().all(|(_, selected)| !*selected)
162 {
163 query_builder
164 } else {
165 let list = statuses
166 .iter()
167 .filter_map(|(label, selected)| {
168 if *selected {
169 Some(label.clone().to_uppercase())
170 } else {
171 None
172 }
173 })
174 .collect::<Vec<_>>();
175
176 query_builder.filter("state", "IN", list)
177 };
178
179 let query = query_builder.sort("createdAt", SortOrder::Desc).build();
180
181 if let Some(client) = edc_connector_context.get_client() {
182 client
183 .contract_negotiations(EdcConnectorApiVersion::V4)
184 .query(query)
185 .await
186 .unwrap_or_default()
187 .into_iter()
188 .map(ContractNegotiationItem::from)
189 .collect()
190 } else {
191 vec![]
192 }
193 },
194 )?;
195
196 let contract_negotiation_items = (*contract_negotiation_items).clone();
197
198 Ok(html!(
199 <ListContractNegotiations
200 contract_negotiation_items={contract_negotiation_items}
201 offset={props.offset}
202 limit={props.limit}
203 switch={props.switch_view_consumer}
204 statuses={props.statuses.clone()}
205 on_offset={props.on_offset.clone()}
206 on_limit={props.on_limit.clone()}
207 on_switch_view_consumer={props.on_switch_view_consumer.clone()}
208 on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
209 on_statuses={props.on_statuses.clone()}
210 show_status_selector={props.show_status_selector}
211 show_consumer_provider_switch={props.show_consumer_provider_switch}
212 />
213 ))
214}