Skip to main content

edc_web_ui/components/
policy_selector.rs

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