Skip to main content

edc_web_components/components/
policy_selector.rs

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