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