Skip to main content

edc_web_components/components/
policy_selector.rs

1use crate::components::PolicyCard;
2use crate::contexts::use_edc_connector_context;
3use crate::models::PolicyDefinitionItem;
4use edc_connector_client::EdcConnectorApiVersion;
5use edc_connector_client::types::query::Query;
6use patternfly_yew::prelude::*;
7use yew::prelude::*;
8use yew::suspense::use_future_with;
9
10#[derive(Clone, Debug, PartialEq, Properties)]
11pub struct PolicySelectorProps {
12  pub selected_policy: Option<PolicyDefinitionItem>,
13  pub onselect: Callback<PolicyDefinitionItem>,
14  #[prop_or("selectable-policy".to_string())]
15  pub select_id: String,
16}
17
18#[component]
19pub fn PolicySelector(props: &PolicySelectorProps) -> Html {
20  html!(
21    <Suspense>
22      <PolicySelectorInner
23        onselect={props.onselect.clone()}
24        selected_policy={props.selected_policy.clone()}
25        select_id={props.select_id.clone()}
26      />
27    </Suspense>
28  )
29}
30
31#[derive(Clone, Debug, PartialEq, Properties)]
32pub struct PolicySelectorInnerProps {
33  pub selected_policy: Option<PolicyDefinitionItem>,
34  pub onselect: Callback<PolicyDefinitionItem>,
35  pub select_id: String,
36}
37
38#[component]
39fn PolicySelectorInner(props: &PolicySelectorInnerProps) -> HtmlResult {
40  let limit = use_state(|| 10usize);
41  let offset = use_state(|| 0usize);
42  let force_refresh = use_state(|| 0usize);
43  let edc_connector_context = use_edc_connector_context();
44
45  let policies = use_future_with(
46    (edc_connector_context, *limit, *offset, *force_refresh),
47    |parameters| async move {
48      let (edc_connector_context, limit, offset, _) = (*parameters).clone();
49
50      let query = Query::builder()
51        .limit(limit as u32)
52        .offset(offset as u32)
53        .build();
54
55      if let Some(client) = edc_connector_context.get_client() {
56        client
57          .policies(EdcConnectorApiVersion::V4)
58          .query(query)
59          .await
60          .unwrap_or_default()
61          .into_iter()
62          .map(PolicyDefinitionItem::from)
63          .collect::<Vec<_>>()
64      } else {
65        vec![]
66      }
67    },
68  )?;
69
70  let policies = (*policies).clone();
71
72  let items = policies.iter().map(|policy_definition_item| {
73    let policy_definition_item = policy_definition_item.clone();
74
75    html!(
76      <PolicyCard
77        policy_definition_item={policy_definition_item.clone()}
78        selected={Some(&policy_definition_item) == props.selected_policy.as_ref()}
79        on_click={props.onselect.reform(move |_| policy_definition_item.clone())}
80      />
81    )
82  });
83
84  let onlimit = use_callback(limit.setter(), |limit, limit_setter| {
85    limit_setter.set(limit)
86  });
87
88  let total_entries = Option::<usize>::None;
89
90  let nav_callback = use_callback(
91    (offset.clone(), *limit, total_entries),
92    |page: Navigation, (offset, limit, total_entries)| {
93      let new_offset = match page {
94        Navigation::First => 0,
95        Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
96        Navigation::Previous => **offset - limit,
97        Navigation::Next => **offset + limit,
98        Navigation::Page(n) => n * limit,
99      };
100      offset.set(new_offset);
101    },
102  );
103
104  Ok(html!(
105    <Stack gutter=true>
106      <StackItem>
107        <Pagination
108          offset={*offset}
109          entries_per_page_choices={vec![5, 10, 25, 50, 100]}
110          selected_choice={*limit}
111          onlimit={&onlimit}
112          onnavigation={&nav_callback}
113        />
114      </StackItem>
115      <StackItem>
116        <Gallery gutter=true>{ for items }</Gallery>
117      </StackItem>
118    </Stack>
119  ))
120}