edc_web_ui/components/
list_contract_definitions.rs1use crate::contexts::use_edc_connector_context;
2use edc_connector_client::types::contract_definition::ContractDefinition;
3use edc_connector_client::types::query::Query;
4use patternfly_yew::prelude::*;
5use std::rc::Rc;
6use yew::platform::spawn_local;
7use yew::prelude::*;
8use yew::suspense::use_future_with;
9
10#[function_component]
11pub fn ListContractDefinitions() -> Html {
12 let fallback = html!("Loading ...");
13
14 html!(
15 <Suspense {fallback}>
16 <ListContractDefinitionsInner />
17 </Suspense>
18 )
19}
20
21#[function_component]
22pub fn ListContractDefinitionsInner() -> HtmlResult {
23 let edc_connector_context = use_edc_connector_context();
24
25 let offset = use_state(|| 0usize);
26 let limit = use_state(|| 10usize);
27
28 let contract_definition_list = use_future_with(
29 (edc_connector_context, *limit, *offset),
30 |parameters| async move {
31 let (edc_connector_context, limit, offset) = &*parameters;
32
33 let query = Query::builder()
34 .limit(*limit as u32)
35 .offset(*offset as u32)
36 .build();
37
38 if let Some(client) = edc_connector_context.get_client() {
39 client.contract_definitions().query(query).await
40 } else {
41 Ok(vec![])
42 }
43 },
44 )?;
45
46 let contract_definition_list = &(*contract_definition_list);
47
48 let header = html_nested! {
49 <TableHeader<Columns>>
50 <TableColumn<Columns> label="ID" index={Columns::Id} />
51 <TableColumn<Columns> label="Access Policy ID" index={Columns::AccessPolicyId} />
52 <TableColumn<Columns> label="Contract Policy ID" index={Columns::ContractPolicyId} />
53 <TableColumn<Columns> label="" index={Columns::Actions} />
54 </TableHeader<Columns>>
55 };
56
57 let limit_callback = use_callback(limit.clone(), |number, limit| limit.set(number));
58
59 let total_entries: Option<usize> = None;
60
61 let nav_callback = use_callback(
62 (offset.clone(), *limit, total_entries),
63 |page: Navigation, (offset, limit, total_entries)| {
64 let o = match page {
65 Navigation::First => 0,
66 Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
67 Navigation::Previous => **offset - limit,
68 Navigation::Next => **offset + limit,
69 Navigation::Page(n) => n * limit,
70 };
71 offset.set(o);
72 },
73 );
74
75 let rows = contract_definition_list
76 .as_ref()
77 .unwrap()
78 .iter()
79 .map(|contract_definition| ContractDefinitionRenderer(contract_definition.clone()))
80 .collect();
81
82 let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
83
84 let table = html!(
85 <>
86 <Toolbar>
87 <ToolbarContent>
88 <ToolbarItem r#type={ToolbarItemType::Pagination}>
89 <Pagination
90 offset={*offset}
91 entries_per_page_choices={vec![5, 10, 25, 50, 100]}
92 selected_choice={*limit}
93 onlimit={&limit_callback}
94 onnavigation={&nav_callback}
95 />
96 </ToolbarItem>
97 </ToolbarContent>
98 </Toolbar>
99 <Table<Columns, UseTableData<Columns, MemoizedTableModel<ContractDefinitionRenderer>>>
100 mode={TableMode::Compact}
101 {header}
102 {entries}
103 />
104 </>
105 );
106
107 Ok(table)
108}
109
110#[derive(Clone, Debug, Eq, PartialEq)]
111enum Columns {
112 Id,
113 AccessPolicyId,
114 ContractPolicyId,
115 Actions,
116}
117
118#[derive(Clone, Debug)]
119struct ContractDefinitionRenderer(ContractDefinition);
120
121impl ContractDefinitionRenderer {}
122
123impl TableEntryRenderer<Columns> for ContractDefinitionRenderer {
124 fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
125 match context.column {
126 Columns::Id => html! {self.0.id().to_string()},
127 Columns::AccessPolicyId => html!(self.0.access_policy_id()),
128 Columns::ContractPolicyId => html!(self.0.contract_policy_id()),
129 Columns::Actions => {
130 let contract_definition_id = self.0.id().to_string();
131
132 html!(
133 <DeleteContractDefinition {contract_definition_id} />
134 )
135 }
136 }
137 .into()
138 }
139}
140
141#[derive(Clone, PartialEq, Properties)]
142pub struct Props {
143 pub contract_definition_id: String,
144}
145
146#[function_component]
147pub fn DeleteContractDefinition(props: &Props) -> Html {
148 let edc_connector_context = use_edc_connector_context();
149
150 let onclick = use_callback(
151 (edc_connector_context, props.contract_definition_id.clone()),
152 move |_, (edc_connector_context, contract_definition_id)| {
153 let edc_connector_context = edc_connector_context.clone();
154 let contract_definition_id = contract_definition_id.to_string();
155
156 spawn_local(async move {
157 if let Some(client) = edc_connector_context.get_client() {
158 let _ = client
159 .contract_definitions()
160 .delete(&contract_definition_id)
161 .await;
162 }
163 });
164 },
165 );
166
167 html!(
168 <Button
169 variant={ButtonVariant::Danger}
170 icon={Icon::Trash}
171 {onclick}
172 >
173 {"Delete"}
174 </Button>
175 )
176}