edc_web_components/pages/
my_published_offer.rs1use crate::components::{AssetCard, DatasetCard, ShowPolicy};
2use crate::contexts::use_edc_connector_context;
3use crate::models::{AssetItem, ContractDefinitionItem, DataspaceDataset};
4use edc_connector_client::EdcConnectorApiVersion;
5use edc_connector_client::types::query::Query;
6use patternfly_yew::prelude::*;
7use yew::platform::spawn_local;
8use yew::prelude::*;
9use yew::suspense::use_future_with;
10
11#[derive(Clone, Debug, PartialEq, Properties)]
12pub struct MyPublishedOfferPageProps {
13 #[prop_or("My Published Offer".to_string())]
14 pub title: String,
15 #[prop_or(None)]
16 pub tag_line: Option<String>,
17 pub asset_id: String,
18}
19
20#[component]
21pub fn MyPublishedOfferPage(props: &MyPublishedOfferPageProps) -> Html {
22 let tag_line = props
23 .tag_line
24 .as_ref()
25 .map(|tag_line| html!(<p>{ tag_line }</p>))
26 .unwrap_or_default();
27
28 html!(
29 <>
30 <Title level={Level::H2} size={Size::XXXLarge}>{ &props.title }</Title>
31 { tag_line }
32 <Suspense fallback={html!{<Bullseye><Spinner/></Bullseye>}}>
33 <MyPublishedOfferPageInner asset_id={props.asset_id.clone()} />
34 </Suspense>
35 </>
36 )
37}
38
39#[component]
40pub fn MyPublishedOfferPageInner(props: &MyPublishedOfferPageProps) -> HtmlResult {
41 let edc_connector_context = use_edc_connector_context();
42
43 let refresh = use_state(|| 0usize);
44
45 let results = use_future_with(
46 (
47 edc_connector_context.clone(),
48 props.asset_id.clone(),
49 refresh.clone(),
50 ),
51 |parameters| async move {
52 let (edc_connector_context, asset_id, _) = (*parameters).clone();
53
54 let query = Query::builder().limit(1000).build();
55
56 if let Some(client) = edc_connector_context.get_client() {
57 let asset = client
58 .assets(EdcConnectorApiVersion::V4)
59 .get(&asset_id)
60 .await
61 .ok()
62 .map(AssetItem::from);
63
64 let contract_definitions = client
65 .contract_definitions(EdcConnectorApiVersion::V4)
66 .query(query)
67 .await
68 .unwrap_or_default()
69 .into_iter()
70 .map(ContractDefinitionItem::from)
71 .filter(|contract_definition_item| contract_definition_item.asset_ids.contains(&asset_id))
72 .collect::<Vec<_>>();
73
74 let mut contract_definitions_and_policies = Vec::with_capacity(contract_definitions.len());
75
76 for contract_definition in contract_definitions.into_iter() {
77 let access_policy = client
78 .policies(EdcConnectorApiVersion::V4)
79 .get(&contract_definition.access_policy_id)
80 .await
81 .ok();
82
83 let contract_policy = client
84 .policies(EdcConnectorApiVersion::V4)
85 .get(&contract_definition.contract_policy_id)
86 .await
87 .ok();
88
89 contract_definitions_and_policies.push((
90 contract_definition,
91 access_policy,
92 contract_policy,
93 ));
94 }
95
96 (contract_definitions_and_policies, asset)
97 } else {
98 (vec![], None)
99 }
100 },
101 )?;
102
103 let (contract_definitions_and_policies, asset_item) = (*results).clone();
104
105 log::trace!("asset_item: {:?}", asset_item);
106 log::trace!(
107 "contract_definitions_and_policies: {:?}",
108 contract_definitions_and_policies
109 );
110
111 let backdropper = use_backdrop();
112
113 let unpublish_offer = use_callback(
114 (
115 edc_connector_context.clone(),
116 refresh.clone(),
117 backdropper.clone(),
118 ),
119 |contract_definition_id: String, (edc_connector_context, refresh, backdropper)| {
120 let edc_connector_context = edc_connector_context.clone();
121 let contract_definition_id = contract_definition_id.clone();
122 let refresh = refresh.clone();
123 let backdropper = backdropper.clone();
124
125 spawn_local(async move {
126 if let Some(client) = edc_connector_context.get_client() {
127 if let Err(error) = client
128 .contract_definitions(EdcConnectorApiVersion::V4)
129 .delete(&contract_definition_id)
130 .await
131 {
132 log::error!("Unable to unpublish offer: {}", error);
133 } else {
134 refresh.set(*refresh + 1);
135 if let Some(backdropper) = backdropper {
136 backdropper.close();
137 }
138 }
139 }
140 });
141 },
142 );
143
144 let unpublish = use_callback(
145 (backdropper.clone(), unpublish_offer.clone()),
146 |contract_definition_item: ContractDefinitionItem, (backdropper, unpublish_offer)| {
147 let contract_definition_id = contract_definition_item.id.clone();
148
149 let assets = contract_definition_item
150 .asset_ids
151 .iter()
152 .map(|asset_id| html!(<AssetCard asset_id={asset_id.clone()} />));
153
154 if let Some(backdropper) = backdropper {
155 backdropper.open(Backdrop::new(
156 html!(
157 <Bullseye>
158 <Modal
159 title={format!("Review Unpublish Offer: {}", contract_definition_item.name)}
160 variant={ModalVariant::Medium}
161 >
162 <Stack gutter=true>
163 <StackItem>
164 { "By unpublishing the offer, it will remove publication of these related asset(s):" }
165 </StackItem>
166 <StackItem>
167 <Gallery gutter=true>{ for assets }</Gallery>
168 </StackItem>
169 <StackItem>
170 <Button
171 variant={ButtonVariant::Danger}
172 onclick={unpublish_offer.reform(move |_| contract_definition_id.clone())}
173 >
174 { "Yes, unpublish this offer" }
175 </Button>
176 </StackItem>
177 </Stack>
178 </Modal>
179 </Bullseye>
180 )
181 ))
182 }
183 },
184 );
185
186 if let Some(asset_item) = asset_item {
187 let dataset = DataspaceDataset::from(asset_item);
188
189 let contract_definitions = contract_definitions_and_policies.iter().map(
190 |(contract_definition_item, access_policy, contract_policy)| {
191 let access_policy = access_policy.as_ref().map(|access_policy| {
192 html!(<ShowPolicy policy={access_policy.policy().clone()} hide_id=true hide_kind=true />)
193 });
194
195 let contract_policy = contract_policy.as_ref().map(|contract_policy| {
196 html!(<ShowPolicy policy={contract_policy.policy().clone()} hide_id=true hide_kind=true />)
197 });
198
199 let name = contract_definition_item.name.clone();
200 let contract_definition_item = contract_definition_item.clone();
201
202 html!(
203 <Card>
204 <CardHeader>
205 <Split>
206 <SplitItem fill=true>{ name }</SplitItem>
207 <SplitItem>
208 <Button
209 variant={ButtonVariant::DangerSecondary}
210 onclick={unpublish.reform(move |_| contract_definition_item.clone())}
211 >
212 { "Unpublish" }
213 </Button>
214 </SplitItem>
215 </Split>
216 </CardHeader>
217 <Divider />
218 <CardBody>
219 <Title level={Level::H6} size={Size::Large}>{ "Access Policy" }</Title>
220 { access_policy }
221 </CardBody>
222 <Divider />
223 <CardBody>
224 <Title level={Level::H6} size={Size::Large}>{ "Contract Policy" }</Title>
225 { contract_policy }
226 </CardBody>
227 </Card>
228 )
229 },
230 );
231
232 Ok(html!(
233 <Stack gutter=true>
234 <StackItem>
235 <DatasetCard {dataset} />
236 </StackItem>
237 <StackItem>
238 <Title level={Level::H4} size={Size::XLarge}>
239 { "Available Terms & Conditions for this Offer" }
240 </Title>
241 <Gallery gutter=true min_widths={AttrValue::from("400px").all()}>
242 { for contract_definitions }
243 </Gallery>
244 </StackItem>
245 </Stack>
246 ))
247 } else {
248 Ok(html!(<Bullseye>{ "Asset not found" }</Bullseye>))
249 }
250}