Skip to main content

edc_web_components/pages/
show_policy_page.rs

1use crate::contexts::use_edc_connector_context;
2use edc_connector_client::types::policy::{Constraint, LeftOperand, Operator, PolicyKind};
3use patternfly_yew::prelude::*;
4use yew::prelude::*;
5use yew::suspense::use_future_with;
6
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct ShowPolicyPageProps {
9  pub policy_id: String,
10}
11
12#[component]
13pub fn ShowPolicyPage(props: &ShowPolicyPageProps) -> Html {
14  html!(
15    <>
16      <Title level={Level::H2} size={Size::XXXLarge}>{ "Show Policy" }</Title>
17      <Suspense fallback="Loading ...">
18        <ShowPolicyPageInner policy_id={props.policy_id.clone()} />
19      </Suspense>
20    </>
21  )
22}
23
24#[component]
25pub fn ShowPolicyPageInner(props: &ShowPolicyPageProps) -> HtmlResult {
26  let edc_connector_client = use_edc_connector_context();
27
28  let policy = use_future_with(
29    (props.policy_id.clone(), edc_connector_client.clone()),
30    |properties| async move {
31      let (policy_id, edc_connector_client) = (*properties).clone();
32
33      if let Some(client) = edc_connector_client.get_client() {
34        client
35          .policies(edc_connector_client::EdcConnectorApiVersion::V4)
36          .get(&policy_id)
37          .await
38          .ok()
39      } else {
40        None
41      }
42    },
43  )?;
44
45  let policy = (*policy).clone();
46
47  if let Some(policy) = policy {
48    let kind = match policy.policy().kind() {
49      PolicyKind::Set => "Set",
50      PolicyKind::Offer => "Offer",
51      PolicyKind::Agreement => "Agreement",
52    };
53
54    let permissions = policy.policy().permissions().iter().map(|permission| {
55      html! {
56        <ConstraintRenderer
57          action={permission.action().clone()}
58          constraints={permission.constraints().to_vec()}
59        />
60      }
61    });
62
63    let obligations = policy.policy().obligations().iter().map(|obligation| {
64      html! {
65        <ConstraintRenderer
66          action={obligation.action().clone()}
67          constraints={obligation.constraints().to_vec()}
68        />
69      }
70    });
71
72    let prohibitions = policy.policy().prohibitions().iter().map(|prohibition| {
73      html! {
74        <ConstraintRenderer
75          action={prohibition.action().clone()}
76          constraints={prohibition.constraints().to_vec()}
77        />
78      }
79    });
80
81    Ok(html!(
82      <DescriptionList mode={[DescriptionListMode::Horizontal]}>
83        <DescriptionGroup term="Id">{ policy.id() }</DescriptionGroup>
84        <DescriptionGroup term="Kind">{ kind }</DescriptionGroup>
85        <DescriptionGroup term="Assigner">
86          { policy.policy().assigner().cloned().unwrap_or_default() }
87        </DescriptionGroup>
88        <DescriptionGroup term="Assignee">
89          { policy.policy().assignee().cloned().unwrap_or_default() }
90        </DescriptionGroup>
91        <DescriptionGroup term="Permissions">{ for permissions }</DescriptionGroup>
92        <DescriptionGroup term="Obligations">{ for obligations }</DescriptionGroup>
93        <DescriptionGroup term="Prohibitions">{ for prohibitions }</DescriptionGroup>
94      </DescriptionList>
95    ))
96  } else {
97    Ok(html!(
98      format!(
99      "Policy with id {} not found.",
100      props.policy_id
101    )
102    ))
103  }
104}
105
106#[derive(Clone, Debug, PartialEq, Properties)]
107pub struct ConstraintRendererProps {
108  pub action: edc_connector_client::types::policy::Action,
109  pub constraints: Vec<Constraint>,
110}
111
112#[component]
113fn ConstraintRenderer(props: &ConstraintRendererProps) -> Html {
114  use edc_connector_client::types::policy::Action;
115
116  let action = match &props.action {
117    Action::Simple(simple) => simple.to_string(),
118    Action::Id { id } => id.to_string(),
119  };
120
121  let constraints = props.constraints.iter().map(|constraint| match constraint {
122    Constraint::Atomic(atomic_constraint) => {
123      let left_operand = match &atomic_constraint.left_operand {
124        LeftOperand::Id { id } => id.to_string(),
125        LeftOperand::Simple(simple) => simple.to_string(),
126      };
127
128      let operator = match &atomic_constraint.operator {
129        Operator::Id { id } => id.to_string(),
130        Operator::Simple(simple) => simple.to_string(),
131      };
132
133      let right_operand = match &atomic_constraint.right_operand.0 {
134        serde_json::Value::String(content) => content.to_string(),
135        value => value.to_string(),
136      };
137
138      html_nested!(
139        <DescriptionGroup term="Contraint">
140          { format!("{left_operand} {operator} {right_operand}") }
141        </DescriptionGroup>
142      )
143    }
144    Constraint::MultiplicityConstraint(multiplicity_constraint) => {
145      html_nested!(
146        <DescriptionGroup term="Multiplicity Constraint">
147          { format!("{multiplicity_constraint:?}") }
148        </DescriptionGroup>
149      )
150    }
151  });
152
153  html! {
154    <>
155      <DescriptionList>
156        <DescriptionGroup term="Action">{ action }</DescriptionGroup>
157        { for constraints }
158      </DescriptionList>
159    </>
160  }
161}