Skip to main content

edc_web_components/components/
list_contract_definitions.rs

1use 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}