Add support for legacy relays API
This commit is contained in:
		@@ -132,12 +132,14 @@ impl ConsumptionHistoryFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use crate::app_config::ConsumptionHistoryType;
 | 
				
			||||||
    use crate::energy::consumption::EnergyConsumption;
 | 
					    use crate::energy::consumption::EnergyConsumption;
 | 
				
			||||||
    use crate::energy::consumption_history_file::{ConsumptionHistoryFile, TIME_INTERVAL};
 | 
					    use crate::energy::consumption_history_file::{ConsumptionHistoryFile, TIME_INTERVAL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_consumption_history() {
 | 
					    fn test_consumption_history() {
 | 
				
			||||||
        let mut history = ConsumptionHistoryFile::new_memory(0);
 | 
					        let mut history =
 | 
				
			||||||
 | 
					            ConsumptionHistoryFile::new_memory(0, ConsumptionHistoryType::GridConsumption);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for i in 0..50 {
 | 
					        for i in 0..50 {
 | 
				
			||||||
            assert_eq!(
 | 
					            assert_eq!(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -399,8 +399,8 @@ impl Handler<GetDevicesState> for EnergyActor {
 | 
				
			|||||||
#[derive(serde::Serialize)]
 | 
					#[derive(serde::Serialize)]
 | 
				
			||||||
pub struct ResRelayState {
 | 
					pub struct ResRelayState {
 | 
				
			||||||
    pub id: DeviceRelayID,
 | 
					    pub id: DeviceRelayID,
 | 
				
			||||||
    on: bool,
 | 
					    pub on: bool,
 | 
				
			||||||
    r#for: usize,
 | 
					    pub r#for: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Get the state of all relays
 | 
					/// Get the state of all relays
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
 | 
				
			|||||||
use crate::energy::consumption::EnergyConsumption;
 | 
					use crate::energy::consumption::EnergyConsumption;
 | 
				
			||||||
use crate::energy::relay_state_history;
 | 
					use crate::energy::relay_state_history;
 | 
				
			||||||
use crate::energy::relay_state_history::RelayStateHistory;
 | 
					use crate::energy::relay_state_history::RelayStateHistory;
 | 
				
			||||||
use crate::utils::time_utils::{curr_hour, time_secs, time_start_of_day};
 | 
					use crate::utils::time_utils::{curr_hour, time_secs};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default)]
 | 
					#[derive(Default)]
 | 
				
			||||||
pub struct DeviceState {
 | 
					pub struct DeviceState {
 | 
				
			||||||
@@ -283,12 +283,7 @@ impl EnergyEngine {
 | 
				
			|||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let time_start_day = time_start_of_day().unwrap_or(1726696800);
 | 
					                let total_runtime = relay_state_history::relay_total_runtime_adjusted(r);
 | 
				
			||||||
                let start_time = time_start_day + constraints.reset_time as u64;
 | 
					 | 
				
			||||||
                let end_time = time_start_day + 3600 * 24 + constraints.reset_time as u64;
 | 
					 | 
				
			||||||
                let total_runtime =
 | 
					 | 
				
			||||||
                    relay_state_history::relay_total_runtime(r.id, start_time, end_time)
 | 
					 | 
				
			||||||
                        .unwrap_or(3600 * 24);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if total_runtime > constraints.min_runtime {
 | 
					                if total_runtime > constraints.min_runtime {
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
@@ -454,7 +449,7 @@ mod test {
 | 
				
			|||||||
    fn run_test(name: &str, conf: &str) {
 | 
					    fn run_test(name: &str, conf: &str) {
 | 
				
			||||||
        let (devices, mut energy_engine, consumption, states) = parse_test_config(conf);
 | 
					        let (devices, mut energy_engine, consumption, states) = parse_test_config(conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        energy_engine.refresh(consumption, &devices);
 | 
					        energy_engine.refresh(consumption, &devices.iter().collect::<Vec<_>>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (device_s, device) in states.iter().zip(&devices) {
 | 
					        for (device_s, device) in states.iter().zip(&devices) {
 | 
				
			||||||
            for (relay_s, relay) in device_s.relays.iter().zip(&device.relays) {
 | 
					            for (relay_s, relay) in device_s.relays.iter().zip(&device.relays) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
use crate::app_config::AppConfig;
 | 
					use crate::app_config::AppConfig;
 | 
				
			||||||
use crate::devices::device::DeviceRelayID;
 | 
					use crate::devices::device::{DeviceRelay, DeviceRelayID};
 | 
				
			||||||
use crate::utils::files_utils;
 | 
					use crate::utils::files_utils;
 | 
				
			||||||
use crate::utils::time_utils::day_number;
 | 
					use crate::utils::time_utils::{day_number, time_start_of_day};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TIME_INTERVAL: usize = 30;
 | 
					const TIME_INTERVAL: usize = 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,6 +119,20 @@ pub fn relay_total_runtime(device_id: DeviceRelayID, from: u64, to: u64) -> anyh
 | 
				
			|||||||
    Ok(total)
 | 
					    Ok(total)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Get the total runtime of a relay taking account of daily reset time
 | 
				
			||||||
 | 
					pub fn relay_total_runtime_adjusted(relay: &DeviceRelay) -> usize {
 | 
				
			||||||
 | 
					    let reset_time = relay
 | 
				
			||||||
 | 
					        .daily_runtime
 | 
				
			||||||
 | 
					        .as_ref()
 | 
				
			||||||
 | 
					        .map(|r| r.reset_time)
 | 
				
			||||||
 | 
					        .unwrap_or(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let time_start_day = time_start_of_day().unwrap_or(1726696800);
 | 
				
			||||||
 | 
					    let start_time = time_start_day + reset_time as u64;
 | 
				
			||||||
 | 
					    let end_time = time_start_day + 3600 * 24 + reset_time as u64;
 | 
				
			||||||
 | 
					    relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use crate::devices::device::DeviceRelayID;
 | 
					    use crate::devices::device::DeviceRelayID;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,8 +44,8 @@ async fn main() -> std::io::Result<()> {
 | 
				
			|||||||
        .expect("Failed to initialize energy actor!")
 | 
					        .expect("Failed to initialize energy actor!")
 | 
				
			||||||
        .start();
 | 
					        .start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let s1 = servers::secure_server(actor);
 | 
					    let s1 = servers::secure_server(actor.clone());
 | 
				
			||||||
    let s2 = servers::unsecure_server();
 | 
					    let s2 = servers::unsecure_server(actor);
 | 
				
			||||||
    future::try_join(s1, s2)
 | 
					    future::try_join(s1, s2)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .expect("Failed to start servers!");
 | 
					        .expect("Failed to start servers!");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,14 +22,15 @@ use openssl::ssl::{SslAcceptor, SslMethod};
 | 
				
			|||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Start unsecure (HTTP) server
 | 
					/// Start unsecure (HTTP) server
 | 
				
			||||||
pub async fn unsecure_server() -> anyhow::Result<()> {
 | 
					pub async fn unsecure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> {
 | 
				
			||||||
    log::info!(
 | 
					    log::info!(
 | 
				
			||||||
        "Unsecure server starting to listen on {} for {}",
 | 
					        "Unsecure server starting to listen on {} for {}",
 | 
				
			||||||
        AppConfig::get().unsecure_listen_address,
 | 
					        AppConfig::get().unsecure_listen_address,
 | 
				
			||||||
        AppConfig::get().unsecure_origin()
 | 
					        AppConfig::get().unsecure_origin()
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    HttpServer::new(|| {
 | 
					    HttpServer::new(move || {
 | 
				
			||||||
        App::new()
 | 
					        App::new()
 | 
				
			||||||
 | 
					            .app_data(web::Data::new(energy_actor.clone()))
 | 
				
			||||||
            .wrap(Logger::default())
 | 
					            .wrap(Logger::default())
 | 
				
			||||||
            .route(
 | 
					            .route(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
@@ -43,6 +44,10 @@ pub async fn unsecure_server() -> anyhow::Result<()> {
 | 
				
			|||||||
                "/pki/{file}",
 | 
					                "/pki/{file}",
 | 
				
			||||||
                web::get().to(unsecure_pki_controller::serve_pki_file),
 | 
					                web::get().to(unsecure_pki_controller::serve_pki_file),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					            .route(
 | 
				
			||||||
 | 
					                "/relay/{id}/legacy_state",
 | 
				
			||||||
 | 
					                web::get().to(unsecure_relay_controller::legacy_state),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .bind(&AppConfig::get().unsecure_listen_address)?
 | 
					    .bind(&AppConfig::get().unsecure_listen_address)?
 | 
				
			||||||
    .run()
 | 
					    .run()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,3 @@
 | 
				
			|||||||
pub mod unsecure_pki_controller;
 | 
					pub mod unsecure_pki_controller;
 | 
				
			||||||
 | 
					pub mod unsecure_relay_controller;
 | 
				
			||||||
pub mod unsecure_server_controller;
 | 
					pub mod unsecure_server_controller;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					use crate::devices::device::DeviceRelayID;
 | 
				
			||||||
 | 
					use crate::energy::{energy_actor, relay_state_history};
 | 
				
			||||||
 | 
					use crate::server::custom_error::HttpResult;
 | 
				
			||||||
 | 
					use crate::server::WebEnergyActor;
 | 
				
			||||||
 | 
					use actix_web::{web, HttpResponse};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Deserialize)]
 | 
				
			||||||
 | 
					pub struct LegacyStateRelay {
 | 
				
			||||||
 | 
					    id: DeviceRelayID,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Legacy relay state
 | 
				
			||||||
 | 
					#[derive(serde::Serialize)]
 | 
				
			||||||
 | 
					pub struct LegacyState {
 | 
				
			||||||
 | 
					    /// Indicates if relay is on or off
 | 
				
			||||||
 | 
					    is_on: bool,
 | 
				
			||||||
 | 
					    /// Relay name
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    /// Duration since last change of state
 | 
				
			||||||
 | 
					    r#for: usize,
 | 
				
			||||||
 | 
					    /// Current grid consumption
 | 
				
			||||||
 | 
					    prod: i32,
 | 
				
			||||||
 | 
					    /// Total uptime since last reset
 | 
				
			||||||
 | 
					    total_uptime: usize,
 | 
				
			||||||
 | 
					    /// Required uptime during a day
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Will be 0 if there is no daily requirements
 | 
				
			||||||
 | 
					    required_uptime: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Get the state of a relay, adapted for old system components
 | 
				
			||||||
 | 
					pub async fn legacy_state(
 | 
				
			||||||
 | 
					    energy_actor: WebEnergyActor,
 | 
				
			||||||
 | 
					    path: web::Path<LegacyStateRelay>,
 | 
				
			||||||
 | 
					) -> HttpResult {
 | 
				
			||||||
 | 
					    let Some(relay) = energy_actor
 | 
				
			||||||
 | 
					        .send(energy_actor::GetSingleRelay(path.id))
 | 
				
			||||||
 | 
					        .await?
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        return Ok(HttpResponse::NotFound().body("Relay not found!"));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let all_states = energy_actor.send(energy_actor::GetAllRelaysState).await?;
 | 
				
			||||||
 | 
					    let Some(state) = all_states.into_iter().find(|r| r.id == path.id) else {
 | 
				
			||||||
 | 
					        return Ok(HttpResponse::InternalServerError().body("Relay status unavailable!"));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let production = energy_actor.send(energy_actor::GetCurrConsumption).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let total_uptime = relay_state_history::relay_total_runtime_adjusted(&relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(HttpResponse::Ok().json(LegacyState {
 | 
				
			||||||
 | 
					        name: relay.name,
 | 
				
			||||||
 | 
					        is_on: state.on,
 | 
				
			||||||
 | 
					        r#for: state.r#for.min(3600 * 24 * 7),
 | 
				
			||||||
 | 
					        prod: production,
 | 
				
			||||||
 | 
					        total_uptime,
 | 
				
			||||||
 | 
					        required_uptime: relay.daily_runtime.map(|r| r.min_runtime).unwrap_or(0),
 | 
				
			||||||
 | 
					    }))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,6 +12,7 @@ pub async fn secure_home() -> HttpResponse {
 | 
				
			|||||||
struct ServerConfig {
 | 
					struct ServerConfig {
 | 
				
			||||||
    auth_disabled: bool,
 | 
					    auth_disabled: bool,
 | 
				
			||||||
    constraints: StaticConstraints,
 | 
					    constraints: StaticConstraints,
 | 
				
			||||||
 | 
					    unsecure_origin: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for ServerConfig {
 | 
					impl Default for ServerConfig {
 | 
				
			||||||
@@ -19,6 +20,7 @@ impl Default for ServerConfig {
 | 
				
			|||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            auth_disabled: AppConfig::get().unsecure_disable_login,
 | 
					            auth_disabled: AppConfig::get().unsecure_disable_login,
 | 
				
			||||||
            constraints: Default::default(),
 | 
					            constraints: Default::default(),
 | 
				
			||||||
 | 
					            unsecure_origin: AppConfig::get().unsecure_origin(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ import { APIClient } from "./ApiClient";
 | 
				
			|||||||
export interface ServerConfig {
 | 
					export interface ServerConfig {
 | 
				
			||||||
  auth_disabled: boolean;
 | 
					  auth_disabled: boolean;
 | 
				
			||||||
  constraints: ServerConstraint;
 | 
					  constraints: ServerConstraint;
 | 
				
			||||||
 | 
					  unsecure_origin: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ServerConstraint {
 | 
					export interface ServerConstraint {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,9 @@ export function DeviceRelays(p: {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function RelayEntryStatus(p: { relay: DeviceRelay }): React.ReactElement {
 | 
					function RelayEntryStatus(
 | 
				
			||||||
 | 
					  p: Readonly<{ relay: DeviceRelay }>
 | 
				
			||||||
 | 
					): React.ReactElement {
 | 
				
			||||||
  const [state, setState] = React.useState<RelayStatus | undefined>();
 | 
					  const [state, setState] = React.useState<RelayStatus | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const load = async () => {
 | 
					  const load = async () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					import LinkIcon from "@mui/icons-material/Link";
 | 
				
			||||||
import RefreshIcon from "@mui/icons-material/Refresh";
 | 
					import RefreshIcon from "@mui/icons-material/Refresh";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  IconButton,
 | 
					  IconButton,
 | 
				
			||||||
@@ -19,6 +20,8 @@ import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
				
			|||||||
import { BoolText } from "../widgets/BoolText";
 | 
					import { BoolText } from "../widgets/BoolText";
 | 
				
			||||||
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
 | 
					import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
 | 
				
			||||||
import { TimeWidget } from "../widgets/TimeWidget";
 | 
					import { TimeWidget } from "../widgets/TimeWidget";
 | 
				
			||||||
 | 
					import { CopyToClipboard } from "../widgets/CopyToClipboard";
 | 
				
			||||||
 | 
					import { ServerApi } from "../api/ServerApi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RelaysListRoute(p: {
 | 
					export function RelaysListRoute(p: {
 | 
				
			||||||
  homeWidget?: boolean;
 | 
					  homeWidget?: boolean;
 | 
				
			||||||
@@ -101,6 +104,7 @@ function RelaysList(p: {
 | 
				
			|||||||
            <TableCell>Priority</TableCell>
 | 
					            <TableCell>Priority</TableCell>
 | 
				
			||||||
            <TableCell>Consumption</TableCell>
 | 
					            <TableCell>Consumption</TableCell>
 | 
				
			||||||
            <TableCell>Status</TableCell>
 | 
					            <TableCell>Status</TableCell>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
          </TableRow>
 | 
					          </TableRow>
 | 
				
			||||||
        </TableHead>
 | 
					        </TableHead>
 | 
				
			||||||
        <TableBody>
 | 
					        <TableBody>
 | 
				
			||||||
@@ -125,6 +129,20 @@ function RelaysList(p: {
 | 
				
			|||||||
                />{" "}
 | 
					                />{" "}
 | 
				
			||||||
                for <TimeWidget diff time={p.status.get(row.id)!.for} />
 | 
					                for <TimeWidget diff time={p.status.get(row.id)!.for} />
 | 
				
			||||||
              </TableCell>
 | 
					              </TableCell>
 | 
				
			||||||
 | 
					              <TableCell>
 | 
				
			||||||
 | 
					                <Tooltip title="Copy legacy api status">
 | 
				
			||||||
 | 
					                  <CopyToClipboard
 | 
				
			||||||
 | 
					                    content={
 | 
				
			||||||
 | 
					                      ServerApi.Config.unsecure_origin +
 | 
				
			||||||
 | 
					                      `/relay/${row.id}/legacy_state`
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <IconButton>
 | 
				
			||||||
 | 
					                      <LinkIcon />
 | 
				
			||||||
 | 
					                    </IconButton>
 | 
				
			||||||
 | 
					                  </CopyToClipboard>
 | 
				
			||||||
 | 
					                </Tooltip>
 | 
				
			||||||
 | 
					              </TableCell>
 | 
				
			||||||
            </TableRow>
 | 
					            </TableRow>
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
        </TableBody>
 | 
					        </TableBody>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										30
									
								
								central_frontend/src/widgets/CopyToClipboard.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								central_frontend/src/widgets/CopyToClipboard.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import { ButtonBase } from "@mui/material";
 | 
				
			||||||
 | 
					import { PropsWithChildren } from "react";
 | 
				
			||||||
 | 
					import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CopyToClipboard(
 | 
				
			||||||
 | 
					  p: PropsWithChildren<{ content: string }>
 | 
				
			||||||
 | 
					): React.ReactElement {
 | 
				
			||||||
 | 
					  const snackbar = useSnackbar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const copy = () => {
 | 
				
			||||||
 | 
					    navigator.clipboard.writeText(p.content);
 | 
				
			||||||
 | 
					    snackbar(`${p.content} copied to clipboard.`);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ButtonBase
 | 
				
			||||||
 | 
					      onClick={copy}
 | 
				
			||||||
 | 
					      style={{
 | 
				
			||||||
 | 
					        display: "inline-block",
 | 
				
			||||||
 | 
					        alignItems: "unset",
 | 
				
			||||||
 | 
					        textAlign: "unset",
 | 
				
			||||||
 | 
					        position: "relative",
 | 
				
			||||||
 | 
					        padding: "0px",
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      disableRipple
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {p.children}
 | 
				
			||||||
 | 
					    </ButtonBase>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user