edc_web_components/components/
list_contract_negotiations.rs1use crate::components::MultiStateSelector;
2use crate::models::ContractNegotiationItem;
3use patternfly_yew::prelude::*;
4use std::rc::Rc;
5use yew::prelude::*;
6
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct ListContractNegotiationsProps {
9 pub contract_negotiation_items: Vec<ContractNegotiationItem>,
10 pub offset: usize,
11 pub limit: usize,
12 pub switch: bool,
13 pub statuses: Vec<(String, bool)>,
14 pub on_offset: Callback<usize>,
15 pub on_limit: Callback<usize>,
16 pub on_switch_view_consumer: Callback<bool>,
17 pub on_show_contract_negotiation: Callback<String>,
18 pub on_statuses: Callback<Vec<(String, bool)>>,
19 #[prop_or(true)]
20 pub show_status_selector: bool,
21 #[prop_or(true)]
22 pub show_consumer_provider_switch: bool,
23}
24
25#[component]
26pub fn ListContractNegotiations(props: &ListContractNegotiationsProps) -> Html {
27 let header = html_nested! {
28 <TableHeader<Columns>>
29 <TableColumn<Columns> label="State" index={Columns::State} />
30 <TableColumn<Columns> label="Contract Agreement ID" index={Columns::ContractAgreementId} />
31 <TableColumn<Columns> label="Counter Party ID" index={Columns::CounterPartyId} />
32 <TableColumn<Columns> label="Protocol" index={Columns::Protocol} />
33 <TableColumn<Columns> label="Kind" index={Columns::Kind} />
34 <TableColumn<Columns> label="" index={Columns::Actions} />
35 </TableHeader<Columns>>
36 };
37
38 let total_entries: Option<usize> = None;
39
40 let nav_callback = use_callback(
41 (
42 props.offset,
43 props.limit,
44 total_entries,
45 props.on_offset.clone(),
46 ),
47 |page: Navigation, (offset, limit, total_entries, on_offset)| {
48 let offset = match page {
49 Navigation::First => 0,
50 Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
51 Navigation::Previous => *offset - limit,
52 Navigation::Next => *offset + limit,
53 Navigation::Page(n) => n * limit,
54 };
55 on_offset.emit(offset);
56 },
57 );
58
59 let rows = props
60 .contract_negotiation_items
61 .iter()
62 .map(
63 |contract_negotiation_item| ContractNegotiationItemRenderer {
64 item: contract_negotiation_item.clone(),
65 on_show_contract_negotiation: props.on_show_contract_negotiation.clone(),
66 },
67 )
68 .collect();
69
70 let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
71
72 let statuses_selector = if props.show_status_selector {
73 html!(
74 <MultiStateSelector
75 selectable_items={props.statuses.clone()}
76 on_selected={props.on_statuses.clone()}
77 />
78 )
79 } else {
80 html!()
81 };
82
83 let consumer_provider_switch = if props.show_consumer_provider_switch {
84 html!(
85 <Switch
86 label="as Consumer"
87 label_off="as Provider"
88 onchange={props.on_switch_view_consumer.clone()}
89 />
90 )
91 } else {
92 html!()
93 };
94
95 html!(
96 <>
97 <Toolbar>
98 <ToolbarContent>
99 <ToolbarItem r#type={ToolbarItemType::BulkSelect}>
100 { consumer_provider_switch }
101 { statuses_selector }
102 </ToolbarItem>
103 <ToolbarItem r#type={ToolbarItemType::Pagination}>
104 <Pagination
105 offset={props.offset}
106 entries_per_page_choices={vec![5, 10, 25, 50, 100]}
107 selected_choice={props.limit}
108 onlimit={&props.on_limit}
109 onnavigation={&nav_callback}
110 />
111 </ToolbarItem>
112 </ToolbarContent>
113 </Toolbar>
114 <Table<Columns, UseTableData<Columns, MemoizedTableModel<ContractNegotiationItemRenderer>>>
115 mode={TableMode::Compact}
116 {header}
117 {entries}
118 />
119 </>
120 )
121}
122
123#[derive(Clone, Debug, Eq, PartialEq)]
124enum Columns {
125 State,
126 ContractAgreementId,
127 CounterPartyId,
128 Protocol,
129 Kind,
130 Actions,
131}
132
133#[derive(Clone, Debug)]
134struct ContractNegotiationItemRenderer {
135 item: ContractNegotiationItem,
136 on_show_contract_negotiation: Callback<String>,
137}
138
139impl TableEntryRenderer<Columns> for ContractNegotiationItemRenderer {
140 fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
141 match context.column {
142 Columns::State => {
143 let color = match self.item.state.as_str() {
144 "Finalized" => Color::Green,
145 "Terminated" => Color::Red,
146 _ => Color::Blue,
147 };
148
149 html! { <Label label={self.item.state.to_string()} {color} /> }
150 },
151 Columns::ContractAgreementId => html! { self.item.contract_agreement_id.to_string() },
152 Columns::CounterPartyId => html! { self.item.counter_party_id.to_string() },
153 Columns::Protocol => html! { self.item.protocol.to_string() },
154 Columns::Kind => html! { self.item.kind.to_string() },
155 Columns::Actions => {
156 let contract_negotiation_id = self.item.id.clone();
157 html! {
158 <Button
159 variant={ButtonVariant::Primary}
160 onclick={self.on_show_contract_negotiation.clone().reform(move |_| contract_negotiation_id.clone())}
161 icon={Icon::Eye}
162 >
163 { "Show" }
164 </Button>
165 }
166 },
167 }
168 .into()
169 }
170}