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