edc_web_components/components/
list_contract_definitions.rs1use crate::components::{AssetReference, PolicyReference};
2use crate::models::ContractDefinitionItem;
3use patternfly_yew::prelude::*;
4use std::rc::Rc;
5use yew::prelude::*;
6
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct ListContractDefinitionsProps {
9 pub contract_definition_items: Vec<ContractDefinitionItem>,
10 pub offset: usize,
11 pub limit: usize,
12 pub onoffset: Callback<usize>,
13 pub onlimit: Callback<usize>,
14 pub ondelete: Callback<String>,
15 #[prop_or_default]
16 pub on_policy_click: Callback<String>,
17 #[prop_or_default]
18 pub on_asset_click: Callback<String>,
19}
20
21#[component]
22pub fn ListContractDefinitions(props: &ListContractDefinitionsProps) -> Html {
23 let header = html_nested! {
24 <TableHeader<Columns>>
25 <TableColumn<Columns> label="Name" index={Columns::Name} />
26 <TableColumn<Columns> label="Access Policy" index={Columns::AccessPolicy} />
27 <TableColumn<Columns> label="Contract Policy" index={Columns::ContractPolicy} />
28 <TableColumn<Columns> label="Assets" index={Columns::Assets} />
29 <TableColumn<Columns> label="" index={Columns::Actions} />
30 </TableHeader<Columns>>
31 };
32
33 let total_entries: Option<usize> = None;
34
35 let nav_callback = use_callback(
36 (
37 props.offset,
38 props.limit,
39 total_entries,
40 props.onoffset.clone(),
41 ),
42 |page: Navigation, (offset, limit, total_entries, onoffset)| {
43 let offset = match page {
44 Navigation::First => 0,
45 Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
46 Navigation::Previous => *offset - limit,
47 Navigation::Next => *offset + limit,
48 Navigation::Page(n) => n * limit,
49 };
50 onoffset.emit(offset);
51 },
52 );
53
54 let rows = props
55 .contract_definition_items
56 .iter()
57 .map(|contract_definition_item| ContractDefinitionItemRenderer {
58 contract_definition_item: contract_definition_item.clone(),
59 ondelete: props.ondelete.clone(),
60 on_policy_click: props.on_policy_click.clone(),
61 on_asset_click: props.on_asset_click.clone(),
62 })
63 .collect();
64
65 let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
66
67 html!(
68 <>
69 <Toolbar>
70 <ToolbarContent>
71 <ToolbarItem r#type={ToolbarItemType::Pagination}>
72 <Pagination
73 offset={props.offset}
74 entries_per_page_choices={vec![5, 10, 25, 50, 100]}
75 selected_choice={props.limit}
76 onlimit={&props.onlimit}
77 onnavigation={&nav_callback}
78 />
79 </ToolbarItem>
80 </ToolbarContent>
81 </Toolbar>
82 <Table<Columns, UseTableData<Columns, MemoizedTableModel<ContractDefinitionItemRenderer>>>
83 mode={TableMode::Compact}
84 {header}
85 {entries}
86 />
87 </>
88 )
89}
90
91#[derive(Clone, Debug, Eq, PartialEq)]
92enum Columns {
93 Name,
94 AccessPolicy,
95 ContractPolicy,
96 Assets,
97 Actions,
98}
99
100#[derive(Clone, Debug)]
101struct ContractDefinitionItemRenderer {
102 contract_definition_item: ContractDefinitionItem,
103 ondelete: Callback<String>,
104 on_policy_click: Callback<String>,
105 on_asset_click: Callback<String>,
106}
107
108impl ContractDefinitionItemRenderer {}
109
110impl TableEntryRenderer<Columns> for ContractDefinitionItemRenderer {
111 fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
112 match context.column {
113 Columns::Name => html! { self.contract_definition_item.name.to_string() },
114 Columns::AccessPolicy => {
115 let access_policy_id = self.contract_definition_item.access_policy_id.to_string();
116 html!(
117 <PolicyReference
118 policy_id={self.contract_definition_item.access_policy_id.to_string()}
119 on_click={self.on_policy_click.reform(move |_| access_policy_id.clone())}
120 />
121 )
122 },
123 Columns::ContractPolicy => {
124 let contract_policy_id = self.contract_definition_item.contract_policy_id.to_string();
125 html!(
126 <PolicyReference
127 policy_id={self.contract_definition_item.contract_policy_id.to_string()}
128 on_click={self.on_policy_click.reform(move |_| contract_policy_id.clone())}
129 />
130 )
131 },
132 Columns::Assets => {
133 let assets = self.contract_definition_item.asset_ids.iter().map(|asset_id| {
134 let asset_id = asset_id.clone();
135
136 html_nested!(
137 <FlexItem>
138 <AssetReference
139 asset_id={asset_id.clone()}
140 on_click={self.on_asset_click.reform(move |_| asset_id.clone())}
141 />
142 </FlexItem>
143 )
144 });
145
146 html!(<Flex>{ for assets }</Flex>)
147 },
148 Columns::Actions => {
149 let contract_definition_id = self.contract_definition_item.id.to_string();
150
151 html!(<DeleteContractDefinition {contract_definition_id} ondelete={self.ondelete.clone()} />)
152 }
153 }
154 .into()
155 }
156}
157
158#[derive(Clone, PartialEq, Properties)]
159pub struct Props {
160 pub contract_definition_id: String,
161 pub ondelete: Callback<String>,
162}
163
164#[function_component]
165pub fn DeleteContractDefinition(props: &Props) -> Html {
166 let onclick = use_callback(
167 (props.ondelete.clone(), props.contract_definition_id.clone()),
168 move |_, (ondelete, contract_definition_id)| {
169 ondelete.emit(contract_definition_id.to_string());
170 },
171 );
172
173 html!(<Button variant={ButtonVariant::Danger} icon={Icon::Trash} {onclick}>{ "Delete" }</Button>)
174}