perspective-viewer 4.4.0

A data visualization and analytics component, especially well-suited for large and/or streaming datasets.
Documentation
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

use perspective_client::config::{Expression, ViewConfigUpdate};

use super::UpdateAndRender;
use super::structural::*;
use crate::presentation::{ColumnLocator, ColumnSettingsTab, OpenColumnSettings, Presentation};
use crate::renderer::Renderer;
use crate::session::Session;
use crate::*;

#[derive(Clone, PartialEq)]
pub struct ExpressionUpdater {
    presentation: Presentation,
    renderer: Renderer,
    session: Session,
}

impl HasPresentation for ExpressionUpdater {
    fn presentation(&self) -> &Presentation {
        &self.presentation
    }
}

impl HasRenderer for ExpressionUpdater {
    fn renderer(&self) -> &Renderer {
        &self.renderer
    }
}

impl HasSession for ExpressionUpdater {
    fn session(&self) -> &Session {
        &self.session
    }
}

pub trait EditExpression: HasPresentation + HasRenderer + HasSession + UpdateAndRender {
    fn get_expression_updater(&self) -> ExpressionUpdater {
        ExpressionUpdater {
            presentation: self.presentation().clone(),
            renderer: self.renderer().clone(),
            session: self.session().clone(),
        }
    }

    /// Spawns a future which will update the expression.
    fn update_expr(&self, old_name: String, new_expr: Expression<'static>) {
        let this = self.get_expression_updater();
        ApiFuture::spawn(async move {
            let update = this
                .session
                .to_props()
                .create_replace_expression_update(&old_name, &new_expr);

            this.update_and_render(update)?.await?;
            this.presentation
                .set_open_column_settings(Some(OpenColumnSettings {
                    locator: Some(ColumnLocator::Expression(new_expr.name.to_string())),
                    tab: Some(ColumnSettingsTab::Attributes),
                }));

            Ok(())
        });
    }

    /// Saves a new expression. Spawns a future.
    fn save_expr(&self, expr: Expression) -> ApiResult<()> {
        let presentation = self.presentation().clone();
        let expr_name: String = expr.name.clone().into();
        let task = {
            let mut serde_exprs = self.session().get_view_config().expressions.clone();
            serde_exprs.insert(&expr);
            self.update_and_render(ViewConfigUpdate {
                expressions: Some(serde_exprs),
                ..Default::default()
            })
        }?;

        ApiFuture::spawn(async move {
            task.await?;
            presentation.set_open_column_settings(Some(OpenColumnSettings {
                locator: Some(ColumnLocator::Expression(expr_name)),
                tab: Some(ColumnSettingsTab::Attributes),
            }));

            Ok(())
        });

        Ok(())
    }

    fn delete_expr(&self, expr_name: &str) -> ApiResult<()> {
        let mut serde_exprs = self.session().get_view_config().expressions.clone();
        serde_exprs.remove(expr_name);
        let config = ViewConfigUpdate {
            expressions: Some(serde_exprs),
            ..ViewConfigUpdate::default()
        };

        let task = self.update_and_render(config)?;
        ApiFuture::spawn(task);
        Ok(())
    }
}

impl<T: HasRenderer + HasSession + HasPresentation + UpdateAndRender> EditExpression for T {}