use crate::components::{AssetReference, PolicyReference};
use crate::models::ContractDefinitionItem;
use patternfly_yew::prelude::*;
use std::rc::Rc;
use yew::prelude::*;
#[derive(Clone, Debug, PartialEq, Properties)]
pub struct ListContractDefinitionsProps {
pub contract_definition_items: Vec<ContractDefinitionItem>,
pub offset: usize,
pub limit: usize,
pub onoffset: Callback<usize>,
pub onlimit: Callback<usize>,
pub ondelete: Callback<String>,
}
#[component]
pub fn ListContractDefinitions(props: &ListContractDefinitionsProps) -> Html {
let header = html_nested! {
<TableHeader<Columns>>
<TableColumn<Columns> label="Name" index={Columns::Name} />
<TableColumn<Columns> label="Access Policy" index={Columns::AccessPolicy} />
<TableColumn<Columns> label="Contract Policy" index={Columns::ContractPolicy} />
<TableColumn<Columns> label="Assets" index={Columns::Assets} />
<TableColumn<Columns> label="" index={Columns::Actions} />
</TableHeader<Columns>>
};
let total_entries: Option<usize> = None;
let nav_callback = use_callback(
(
props.offset,
props.limit,
total_entries,
props.onoffset.clone(),
),
|page: Navigation, (offset, limit, total_entries, onoffset)| {
let offset = match page {
Navigation::First => 0,
Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
Navigation::Previous => *offset - limit,
Navigation::Next => *offset + limit,
Navigation::Page(n) => n * limit,
};
onoffset.emit(offset);
},
);
let rows = props
.contract_definition_items
.iter()
.map(|contract_definition_item| ContractDefinitionItemRenderer {
contract_definition_item: contract_definition_item.clone(),
ondelete: props.ondelete.clone(),
})
.collect();
let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
html!(
<>
<Toolbar>
<ToolbarContent>
<ToolbarItem r#type={ToolbarItemType::Pagination}>
<Pagination
offset={props.offset}
entries_per_page_choices={vec![5, 10, 25, 50, 100]}
selected_choice={props.limit}
onlimit={&props.onlimit}
onnavigation={&nav_callback}
/>
</ToolbarItem>
</ToolbarContent>
</Toolbar>
<Table<Columns, UseTableData<Columns, MemoizedTableModel<ContractDefinitionItemRenderer>>>
mode={TableMode::Compact}
{header}
{entries}
/>
</>
)
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum Columns {
Name,
AccessPolicy,
ContractPolicy,
Assets,
Actions,
}
#[derive(Clone, Debug)]
struct ContractDefinitionItemRenderer {
contract_definition_item: ContractDefinitionItem,
ondelete: Callback<String>,
}
impl ContractDefinitionItemRenderer {}
impl TableEntryRenderer<Columns> for ContractDefinitionItemRenderer {
fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
match context.column {
Columns::Name => html! { self.contract_definition_item.name.to_string() },
Columns::AccessPolicy => {
html!(
<PolicyReference
policy_id={self.contract_definition_item.access_policy_id.to_string()}
show_with_modal=true
/>
)
},
Columns::ContractPolicy => {
html!(
<PolicyReference
policy_id={self.contract_definition_item.contract_policy_id.to_string()}
show_with_modal=true
/>
)
},
Columns::Assets => {
let assets = self.contract_definition_item.asset_ids.iter().map(|asset_id| {
html_nested!(
<FlexItem>
<AssetReference asset_id={asset_id.clone()} />
</FlexItem>
)
});
html!(<Flex>{ for assets }</Flex>)
},
Columns::Actions => {
let contract_definition_id = self.contract_definition_item.id.to_string();
html!(<DeleteContractDefinition {contract_definition_id} ondelete={self.ondelete.clone()} />)
}
}
.into()
}
}
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub contract_definition_id: String,
pub ondelete: Callback<String>,
}
#[function_component]
pub fn DeleteContractDefinition(props: &Props) -> Html {
let onclick = use_callback(
(props.ondelete.clone(), props.contract_definition_id.clone()),
move |_, (ondelete, contract_definition_id)| {
ondelete.emit(contract_definition_id.to_string());
},
);
html!(<Button variant={ButtonVariant::Danger} icon={Icon::Trash} {onclick}>{ "Delete" }</Button>)
}