Skip to main content

edc_web_ui/components/
list_assets.rs

1use crate::models::AssetItem;
2use patternfly_yew::prelude::*;
3use std::rc::Rc;
4use yew::prelude::*;
5
6#[derive(Clone, Debug, PartialEq, Properties)]
7pub struct ListAssetsProps {
8  pub asset_items: Vec<AssetItem>,
9  pub offset: usize,
10  pub limit: usize,
11  pub onoffset: Callback<usize>,
12  pub onlimit: Callback<usize>,
13  pub ondelete: Callback<String>,
14}
15
16#[component]
17pub fn ListAssets(props: &ListAssetsProps) -> Html {
18  let header = html_nested! {
19    <TableHeader<Columns>>
20      <TableColumn<Columns> label="Name" index={Columns::Name} />
21      <TableColumn<Columns> label="ID" index={Columns::Id} />
22      <TableColumn<Columns> label="Base URL" index={Columns::BaseUrl} />
23      <TableColumn<Columns> label="Proxy Path" index={Columns::ProxyPath} />
24      <TableColumn<Columns> label="Proxy Query Parameters" index={Columns::ProxyQueryParameters} />
25      <TableColumn<Columns> label="Proxy Method" index={Columns::ProxyMethod} />
26      <TableColumn<Columns> label="Proxy Body" index={Columns::ProxyBody} />
27      <TableColumn<Columns> label="" index={Columns::Actions} />
28    </TableHeader<Columns>>
29  };
30
31  let total_entries: Option<usize> = None;
32
33  let nav_callback = use_callback(
34    (
35      props.offset,
36      props.limit,
37      total_entries,
38      props.onoffset.clone(),
39    ),
40    |page: Navigation, (offset, limit, total_entries, onoffset)| {
41      let offset = match page {
42        Navigation::First => 0,
43        Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
44        Navigation::Previous => *offset - limit,
45        Navigation::Next => *offset + limit,
46        Navigation::Page(n) => n * limit,
47      };
48
49      onoffset.emit(offset);
50    },
51  );
52
53  let rows = props
54    .asset_items
55    .iter()
56    .map(|asset_item| AssetRenderer {
57      asset_item: asset_item.clone(),
58      ondelete: props.ondelete.clone(),
59    })
60    .collect();
61
62  let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
63
64  html!(
65    <>
66      <Toolbar>
67        <ToolbarContent>
68          <ToolbarItem r#type={ToolbarItemType::Pagination}>
69            <Pagination
70              offset={props.offset}
71              entries_per_page_choices={vec![5, 10, 25, 50, 100]}
72              selected_choice={props.limit}
73              onlimit={&props.onlimit}
74              onnavigation={&nav_callback}
75            />
76          </ToolbarItem>
77        </ToolbarContent>
78      </Toolbar>
79      <Table<Columns, UseTableData<Columns, MemoizedTableModel<AssetRenderer>>>
80        mode={TableMode::Compact}
81        {header}
82        {entries}
83      />
84    </>
85  )
86}
87
88#[derive(Clone, Debug, Eq, PartialEq)]
89enum Columns {
90  Id,
91  Name,
92  BaseUrl,
93  ProxyPath,
94  ProxyQueryParameters,
95  ProxyMethod,
96  ProxyBody,
97  Actions,
98}
99
100#[derive(Clone, Debug)]
101struct AssetRenderer {
102  asset_item: AssetItem,
103  ondelete: Callback<String>,
104}
105
106impl TableEntryRenderer<Columns> for AssetRenderer {
107  fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
108    match context.column {
109      Columns::Id => html! { self.asset_item.id.to_owned() },
110      Columns::Name => html!(self.asset_item.name.to_owned()),
111      Columns::BaseUrl => html!(self.asset_item.base_url.to_owned()),
112      Columns::ProxyPath => html!(self.asset_item.proxy_path),
113      Columns::ProxyQueryParameters => html!(self.asset_item.proxy_query_params),
114      Columns::ProxyMethod => html!(self.asset_item.proxy_method),
115      Columns::ProxyBody => html!(self.asset_item.proxy_body),
116      Columns::Actions => {
117        let asset_id = self.asset_item.id.to_string();
118
119        html!(<DeleteAsset {asset_id} ondelete={self.ondelete.clone()} />)
120      }
121    }
122    .into()
123  }
124}
125
126#[derive(Clone, PartialEq, Properties)]
127pub struct Props {
128  pub asset_id: String,
129  pub ondelete: Callback<String>,
130}
131
132#[function_component]
133pub fn DeleteAsset(props: &Props) -> Html {
134  let onclick = use_callback(
135    (props.asset_id.clone(), props.ondelete.clone()),
136    move |_, (asset_id, ondelete)| {
137      ondelete.emit(asset_id.to_string());
138    },
139  );
140
141  html!(<Button variant={ButtonVariant::Danger} icon={Icon::Trash} {onclick}>{ "Delete" }</Button>)
142}