Skip to main content

edc_web_components/components/
create_policy.rs

1mod atomic_constraint_edit;
2mod list_of_rules;
3mod operator_selector;
4mod rule;
5
6pub use self::atomic_constraint_edit::AtomicConstraintEdit;
7pub use self::list_of_rules::ListOfRules;
8pub use self::operator_selector::OperatorSelector;
9pub use self::rule::Rule;
10use crate::components::create_policy::atomic_constraint_edit::ConstraintMode;
11use crate::components::simple_or_id_field::SimpleOrIdField;
12use crate::components::{ExtensiblePropertiesEdit, StringListEdit};
13use crate::contexts::use_edc_connector_context;
14use edc_connector_client::types::policy::{
15  Action, Constraint, NewPolicyDefinition, Obligation, Permission, Policy, PolicyKind, Prohibition,
16  Target,
17};
18use edc_connector_client::{EdcConnectorApiVersion, Error, ManagementApiErrorDetailKind};
19use patternfly_yew::prelude::*;
20use std::collections::HashMap;
21use uuid::Uuid;
22use yew::platform::spawn_local;
23use yew::prelude::*;
24
25#[derive(Clone, Debug, PartialEq, Properties)]
26pub struct CreatePolicyProps {
27  #[prop_or_default]
28  pub on_create: Callback<()>,
29}
30
31#[component]
32pub fn CreatePolicy(props: &CreatePolicyProps) -> Html {
33  let edc_connector_context = use_edc_connector_context();
34
35  let name = use_state(String::new);
36  let assignee = use_state(String::default);
37  let assigner = use_state(String::default);
38  let target = use_state(|| (true, String::default()));
39  let permissions = use_state(Vec::new);
40  let prohibitions = use_state(Vec::new);
41  let obligations = use_state(Vec::new);
42  let profiles = use_state(Vec::new);
43  let extensible_properties = use_state(HashMap::new);
44
45  let creation_errors = use_state(|| None);
46
47  let onsubmit = use_callback(
48    (
49      edc_connector_context,
50      name.clone(),
51      assignee.clone(),
52      assigner.clone(),
53      target.clone(),
54      permissions.clone(),
55      prohibitions.clone(),
56      obligations.clone(),
57      profiles.clone(),
58      extensible_properties.clone(),
59      props.on_create.clone(),
60      creation_errors.setter(),
61    ),
62    |event: SubmitEvent,
63     (
64      edc_connector_context,
65      name,
66      assignee,
67      assigner,
68      target,
69      permissions,
70      prohibitions,
71      obligations,
72      profiles,
73      extensible_properties,
74      on_create,
75      creation_errors_setter,
76    )| {
77      event.prevent_default();
78
79      let edc_connector_context = edc_connector_context.clone();
80      let name = (**name).clone();
81      let profiles = (**profiles).clone();
82      let extensible_properties = (**extensible_properties).clone();
83      let assignee = (**assignee).clone();
84      let assigner = (**assigner).clone();
85      let (is_simple_target, target) = (**target).clone();
86
87      let permissions = (**permissions)
88        .iter()
89        .map(
90          |(action, constraints): &(Action, Vec<(ConstraintMode, Constraint)>)| {
91            Permission::builder()
92              .action(action.clone())
93              .constraints(
94                constraints
95                  .iter()
96                  .map(|(_, constraint)| constraint.clone())
97                  .collect(),
98              )
99              .build()
100          },
101        )
102        .collect();
103
104      let prohibitions = (**prohibitions)
105        .iter()
106        .map(
107          |(action, constraints): &(Action, Vec<(ConstraintMode, Constraint)>)| {
108            Prohibition::builder()
109              .action(action.clone())
110              .constraints(
111                constraints
112                  .iter()
113                  .map(|(_, constraint)| constraint.clone())
114                  .collect(),
115              )
116              .build()
117          },
118        )
119        .collect();
120
121      let obligations = (**obligations)
122        .iter()
123        .map(
124          |(action, constraints): &(Action, Vec<(ConstraintMode, Constraint)>)| {
125            Obligation::builder()
126              .action(action.clone())
127              .constraints(
128                constraints
129                  .iter()
130                  .map(|(_, constraint)| constraint.clone())
131                  .collect(),
132              )
133              .build()
134          },
135        )
136        .collect();
137
138      creation_errors_setter.set(None);
139
140      let on_create = on_create.clone();
141      let creation_errors_setter = creation_errors_setter.clone();
142
143      spawn_local(async move {
144        let kind = PolicyKind::Set;
145
146        let policy_builder = Policy::builder()
147          .kind(kind)
148          .permissions(permissions)
149          .prohibitions(prohibitions)
150          .obligations(obligations)
151          .profiles(profiles)
152          .extensible_properties(extensible_properties);
153
154        let policy_builder = if !assignee.is_empty() {
155          policy_builder.maybe_assignee(Some(assignee))
156        } else {
157          policy_builder.maybe_assignee(None::<String>)
158        };
159
160        let policy_builder = if !assigner.is_empty() {
161          policy_builder.maybe_assigner(Some(assigner))
162        } else {
163          policy_builder.maybe_assigner(None::<String>)
164        };
165
166        let policy_builder = if !target.is_empty() {
167          if is_simple_target {
168            policy_builder.target(Target::Simple(target))
169          } else {
170            policy_builder.target(Target::Id { id: target })
171          }
172        } else {
173          policy_builder.maybe_target(None::<Target>)
174        };
175
176        let policy = policy_builder.build();
177
178        let new_policy = NewPolicyDefinition::builder()
179          .id(Uuid::new_v4().to_string())
180          .policy(policy)
181          .private_property("name", name)
182          .build();
183
184        if let Some(client) = edc_connector_context.get_client() {
185          if let Err(error) = client
186            .policies(EdcConnectorApiVersion::V4)
187            .create(&new_policy)
188            .await
189          {
190            match error {
191              Error::ManagementApi(management_api_error) => {
192                let error_message = match management_api_error.error_detail {
193                  ManagementApiErrorDetailKind::Raw(error) => html!(<div>{ error }</div>),
194                  ManagementApiErrorDetailKind::Parsed(error_list) => error_list
195                    .into_iter()
196                    .map(|error| html!(<div>{ error.message }</div>))
197                    .collect::<Html>(),
198                };
199
200                creation_errors_setter.set(Some(error_message));
201              }
202              _ => {
203                let error_message = format!("{error:?}");
204                creation_errors_setter.set(Some(html!(<div>{ error_message }</div>)));
205              }
206            }
207          } else {
208            on_create.emit(());
209          }
210        }
211      })
212    },
213  );
214
215  let onchange_name = use_callback(name.setter(), move |name, name_setter| {
216    name_setter.set(name);
217  });
218
219  let onchange_assignee = use_callback(
220    assignee.setter(),
221    move |assignee: String, assignee_setter| {
222      assignee_setter.set(assignee);
223    },
224  );
225
226  let onchange_assigner = use_callback(
227    assigner.setter(),
228    move |assigner: String, assigner_setter| {
229      assigner_setter.set(assigner);
230    },
231  );
232
233  let onchange_target = use_callback(
234    target.setter(),
235    move |target: (bool, String), target_setter| {
236      target_setter.set(target);
237    },
238  );
239
240  let onchange_permissions = use_callback(
241    permissions.setter(),
242    move |permissions, permissions_setter| {
243      permissions_setter.set(permissions);
244    },
245  );
246
247  let onchange_prohibitions = use_callback(
248    prohibitions.setter(),
249    move |prohibitions, prohibitions_setter| {
250      prohibitions_setter.set(prohibitions);
251    },
252  );
253
254  let onchange_obligations = use_callback(
255    obligations.setter(),
256    move |obligations, obligations_setter| {
257      obligations_setter.set(obligations);
258    },
259  );
260
261  let onchange_profiles = use_callback(profiles.setter(), move |profiles, profiles_setter| {
262    profiles_setter.set(profiles);
263  });
264
265  let onchange_extensible_properties = use_callback(
266    extensible_properties.setter(),
267    move |extensible_properties, extensible_properties_setter| {
268      extensible_properties_setter.set(extensible_properties);
269    },
270  );
271
272  let (target_is_simple, target_value) = (*target).clone();
273
274  let disabled = false;
275
276  let errors = if let Some(error_mesage) = (*creation_errors).clone() {
277    html!(
278      <Alert title="Unable to create the policy" r#type={AlertType::Danger}>{ error_mesage }</Alert>
279    )
280  } else {
281    html!()
282  };
283
284  html!(
285    <Form {onsubmit}>
286      { errors }
287      <FormGroup label="Name" required=true>
288        <TextInput required=true value={(*name).to_string()} onchange={onchange_name} />
289      </FormGroup>
290      <FormGroup label="Permissions">
291        <ListOfRules list={(*permissions).clone()} onchange={onchange_permissions} />
292      </FormGroup>
293      <FormGroup label="Prohibitions">
294        <ListOfRules list={(*prohibitions).clone()} onchange={onchange_prohibitions} />
295      </FormGroup>
296      <FormGroup label="Obligations">
297        <ListOfRules list={(*obligations).clone()} onchange={onchange_obligations} />
298      </FormGroup>
299      <FormGroup label="Profiles">
300        <StringListEdit values={(*profiles).clone()} onchange={onchange_profiles} />
301      </FormGroup>
302      <FormGroup label="Extensible Properties">
303        <ExtensiblePropertiesEdit
304          values={(*extensible_properties).clone()}
305          onchange={onchange_extensible_properties}
306        />
307      </FormGroup>
308      <FormGroup label="Assignee">
309        <TextInput value={(*assignee).clone()} onchange={onchange_assignee} />
310      </FormGroup>
311      <FormGroup label="Assigner">
312        <TextInput value={(*assigner).clone()} onchange={onchange_assigner} />
313      </FormGroup>
314      <FormGroup label="Target">
315        <SimpleOrIdField
316          onchange={onchange_target}
317          is_simple={target_is_simple}
318          value={target_value}
319        />
320      </FormGroup>
321      <ActionGroup>
322        <Button
323          variant={ButtonVariant::Primary}
324          label="Submit"
325          r#type={ButtonType::Submit}
326          {disabled}
327        />
328        <Button variant={ButtonVariant::Secondary} label="Reset" r#type={ButtonType::Reset} />
329      </ActionGroup>
330    </Form>
331  )
332}