edc_web_components/components/
policy_selector.rs1use 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}