edc-web-ui 0.1.0

A Rust Web interface with patternfly-yew client for EDC
Documentation
use crate::components::atomic_constraint_edit::AtomicConstraintEdit;
use crate::components::simple_or_id_field::SimpleOrIdField;
use edc_connector_client::types::policy::{Action, AtomicConstraint, Constraint};
use edc_connector_client::types::properties::PropertyValue;
use patternfly_yew::prelude::*;
use yew::prelude::*;

#[derive(Clone, PartialEq, Properties)]
pub struct Props {
  pub index: usize,
  pub action: Action,
  pub constraints: Vec<Constraint>,
  pub onchange: Callback<(usize, Action, Vec<Constraint>)>,
  pub ondelete: Callback<usize>,
}

#[function_component]
pub fn Rule(props: &Props) -> Html {
  let action = use_state(|| props.action.clone());
  let constraints = use_state(|| props.constraints.clone());

  let onchange_action = {
    let action = action.clone();

    use_callback(
      (constraints.clone(), props.index, props.onchange.clone()),
      move |(is_simple, value), (constraints, index, onchange)| {
        let value = if is_simple {
          Action::Simple(value)
        } else {
          Action::Id { id: value }
        };

        action.set(value.clone());
        onchange.emit((*index, value, (**constraints).clone()));
      },
    )
  };

  let add_constraint = use_callback(
    (
      action.clone(),
      constraints.clone(),
      props.index,
      props.onchange.clone(),
    ),
    |_, (action, constraints, index, onchange)| {
      let mut list = (**constraints).clone();

      list.push(Constraint::Atomic(AtomicConstraint::new("", "", "")));
      constraints.set(list.clone());

      onchange.emit((*index, (**action).clone(), list));
    },
  );

  let delete_constraint = use_callback(
    (
      action.clone(),
      constraints.clone(),
      props.index,
      props.onchange.clone(),
    ),
    move |contraint_index, (action, constraints, index, onchange)| {
      let mut list = (**constraints).clone();
      list.remove(contraint_index);
      constraints.set(list.clone());

      onchange.emit((*index, (**action).clone(), list));
    },
  );

  let delete_rule = use_callback(
    (props.index, props.ondelete.clone()),
    |_, (index, ondelete)| {
      ondelete.emit(*index);
    },
  );

  let update_constraint = use_callback(
    (
      action.clone(),
      constraints.clone(),
      props.index,
      props.onchange.clone(),
    ),
    |(id, left_operand, operator, right_operand), (action, constraints, index, onchange)| {
      let mut list = (**constraints).clone();

      list[id] = Constraint::Atomic(AtomicConstraint {
        left_operand,
        operator,
        right_operand: PropertyValue(right_operand),
      });

      constraints.set(list.clone());

      onchange.emit((*index, (**action).clone(), list));
    },
  );

  let list_of_constraints = (*constraints)
    .iter()
    .enumerate()
    .map(|(index, constraint)| {
      let inner = match constraint {
        Constraint::Atomic(atomic_constraint) => {
          html!(
            <AtomicConstraintEdit
              key={index}
              {index}
              left_operand={atomic_constraint.left_operand.clone()}
              operator={atomic_constraint.operator.clone()}
              right_operand={atomic_constraint.right_operand.0.clone()}
              onchange={update_constraint.clone()}
              ondelete={delete_constraint.clone()}
              />
          )
        }
        Constraint::MultiplicityConstraint(_) => {
          html!()
        }
      };

      html_nested!(
        <StackItem>
          {inner}
        </StackItem>
      )
    });

  let (action_is_simple, action_value) = match (*action).clone() {
    Action::Simple(value) => (true, value),
    Action::Id { id } => (false, id),
  };

  html!(
    <Stack gutter=true>
      {for list_of_constraints}
      <StackItem>
        <Button
          icon={Icon::Plus}
          variant={ButtonVariant::Primary}
          onclick={add_constraint}
          >
          {"Add Constraint"}
        </Button>
      </StackItem>
      <StackItem>
        <SimpleOrIdField
          onchange={onchange_action}
          is_simple={action_is_simple}
          value={action_value}
          />
      </StackItem>
      <StackItem>
        <Button
          icon={Icon::Trash}
          variant={ButtonVariant::DangerSecondary}
          onclick={delete_rule}
          >
          {"Delete rule"}
        </Button>
      </StackItem>
    </Stack>
  )
}