edc-web-components 0.4.13

A Rust Web Components with patternfly-yew client for EDC
Documentation
use crate::components::ListContractNegotiations;
use crate::contexts::use_edc_connector_context;
use crate::models::ContractNegotiationItem;
use edc_connector_client::EdcConnectorApiVersion;
use edc_connector_client::types::query::{Query, SortOrder};
use patternfly_yew::prelude::*;
use yew::prelude::*;
use yew::suspense::use_future_with;

#[derive(Clone, Debug, PartialEq, Properties)]
pub struct ContractNegotiationPageProps {
  pub on_show_contract_negotiation: Callback<String>,
}

#[component]
pub fn ContractNegotiationPage(props: &ContractNegotiationPageProps) -> Html {
  let refresh = use_state(|| 0usize);
  let offset = use_state(|| 0usize);
  let limit = use_state(|| 10usize);
  let switch_view_consumer = use_state(|| false);
  let statuses = use_state(|| {
    vec![
      ("Initial".to_string(), false),
      ("Requesting".to_string(), false),
      ("Requested".to_string(), false),
      ("Offering".to_string(), false),
      ("Offered".to_string(), false),
      ("Accepting".to_string(), false),
      ("Accepted".to_string(), false),
      ("Agreeing".to_string(), false),
      ("Agreed".to_string(), false),
      ("Verifying".to_string(), false),
      ("Verified".to_string(), false),
      ("Finalizing".to_string(), false),
      ("Finalized".to_string(), false),
      ("Terminating".to_string(), false),
      ("Terminated".to_string(), false),
    ]
  });

  let on_offset = use_callback(
    (refresh.clone(), offset.setter()),
    |offset, (refresh, offset_setter)| {
      offset_setter.set(offset);
      refresh.set(**refresh + 1);
    },
  );

  let on_limit = use_callback(
    (refresh.clone(), limit.setter()),
    |limit, (refresh, limit_setter)| {
      limit_setter.set(limit);
      refresh.set(**refresh + 1);
    },
  );

  let on_switch_view_consumer = use_callback(
    (refresh.clone(), switch_view_consumer.setter()),
    |switch, (refresh, switch_setter)| {
      switch_setter.set(switch);
      refresh.set(**refresh + 1);
    },
  );

  let on_statuses = use_callback(
    (refresh.clone(), statuses.setter()),
    |statuses, (refresh, statuses_setter)| {
      statuses_setter.set(statuses);
      refresh.set(**refresh + 1);
    },
  );

  let fallback = html! {
    <Bullseye>
      <Spinner size={SpinnerSize::Lg} />
    </Bullseye>
  };

  html!(
    <Stack gutter=true>
      <StackItem>
        <Split gutter=true>
          <SplitItem fill=true>
            <Title level={Level::H3} size={Size::XXLarge}>{ "List Contract Negotiations" }</Title>
            <p>
              { "A contract negotiation represents the active, multi-step process between two parties to agree on data sharing terms." }
            </p>
          </SplitItem>
        </Split>
      </StackItem>
      <StackItem>
        <Suspense {fallback}>
          <ContractNegotiationPageInner
            offset={*offset}
            limit={*limit}
            switch_view_consumer={*switch_view_consumer}
            statuses={(*statuses).clone()}
            {on_offset}
            {on_limit}
            {on_switch_view_consumer}
            {on_statuses}
            force_refresh={*refresh}
            on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
          />
        </Suspense>
      </StackItem>
    </Stack>
  )
}

#[derive(Clone, Debug, PartialEq, Properties)]
pub struct ContractNegotiationPageInnerProps {
  pub offset: usize,
  pub limit: usize,
  pub switch_view_consumer: bool,
  #[prop_or_default]
  pub statuses: Vec<(String, bool)>,
  pub on_offset: Callback<usize>,
  pub on_limit: Callback<usize>,
  pub on_switch_view_consumer: Callback<bool>,
  pub on_statuses: Callback<Vec<(String, bool)>>,
  pub force_refresh: usize,
  pub on_show_contract_negotiation: Callback<String>,
}

#[component]
pub fn ContractNegotiationPageInner(props: &ContractNegotiationPageInnerProps) -> HtmlResult {
  let edc_connector_context = use_edc_connector_context();

  let contract_negotiation_items = use_future_with(
    (
      edc_connector_context,
      props.limit,
      props.offset,
      props.switch_view_consumer,
      props.statuses.clone(),
      props.force_refresh,
    ),
    |parameters| async move {
      let (edc_connector_context, limit, offset, switch_view_consumer, statuses, _) =
        (*parameters).clone();

      let query_builder = Query::builder()
        .limit(limit as u32)
        .offset(offset as u32)
        .filter(
          "type",
          "=",
          if switch_view_consumer {
            "CONSUMER"
          } else {
            "PROVIDER"
          },
        );

      let query_builder = if statuses.iter().all(|(_, selected)| *selected)
        || statuses.iter().all(|(_, selected)| !*selected)
      {
        query_builder
      } else {
        let list = statuses
          .iter()
          .filter_map(|(label, selected)| {
            if *selected {
              Some(label.clone().to_uppercase())
            } else {
              None
            }
          })
          .collect::<Vec<_>>();

        query_builder.filter("state", "IN", list)
      };

      let query = query_builder.sort("createdAt", SortOrder::Desc).build();

      if let Some(client) = edc_connector_context.get_client() {
        client
          .contract_negotiations(EdcConnectorApiVersion::V4)
          .query(query)
          .await
          .unwrap_or_default()
          .into_iter()
          .map(ContractNegotiationItem::from)
          .collect()
      } else {
        vec![]
      }
    },
  )?;

  let contract_negotiation_items = (*contract_negotiation_items).clone();

  Ok(html!(
    <ListContractNegotiations
      contract_negotiation_items={contract_negotiation_items}
      offset={props.offset}
      limit={props.limit}
      switch={props.switch_view_consumer}
      statuses={props.statuses.clone()}
      on_offset={props.on_offset.clone()}
      on_limit={props.on_limit.clone()}
      on_switch_view_consumer={props.on_switch_view_consumer.clone()}
      on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
      on_statuses={props.on_statuses.clone()}
    />
  ))
}