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