apalis-board-web 1.0.0-rc.8

Frontend components for managing Apalis task queues.
Documentation
use crate::{config::API_PATH, pages::workers::Worker};
use gloo_net::http::Request;
use leptos::prelude::{GetUntracked, Signal, Track};
use leptos_struct_table::{ColumnSort, TableDataProvider};
use std::{collections::VecDeque, ops::Range};

pub struct WorkerProvider {
    sorting: VecDeque<(usize, ColumnSort)>,
    queue: Option<Signal<String>>,
}

impl WorkerProvider {
    pub fn all() -> Self {
        Self {
            sorting: VecDeque::new(),
            queue: None,
        }
    }
    pub fn new(queue: Signal<String>) -> Self {
        Self {
            sorting: VecDeque::new(),
            queue: Some(queue),
        }
    }
    fn url_sort_param_for_column(&self, column: usize) -> &'static str {
        match column {
            0 => "name",
            1 => "backend",
            2 => "started_at",
            3 => "last_heartbeat",
            4 => "service",
            _ => "",
        }
    }

    fn url_sort_param_for_sort_pair(&self, pair: &(usize, ColumnSort)) -> String {
        let col = self.url_sort_param_for_column(pair.0);

        let dir = match pair.1 {
            ColumnSort::Ascending => "asc",
            ColumnSort::Descending => "desc",
            ColumnSort::None => return "".to_string(),
        };

        format!("sort={col}:{dir}")
    }

    fn get_url(&self) -> String {
        let mut sort = String::new();
        for pair in &self.sorting {
            sort.push_str(&self.url_sort_param_for_sort_pair(pair));
        }
        match self.queue.map(|s| s.get_untracked()) {
            Some(ref q) if !q.is_empty() => {
                format!("{API_PATH}/queues/{q}/workers?{sort}",)
            }
            _ => {
                format!("{API_PATH}/workers?{sort}",)
            }
        }
    }
}

impl TableDataProvider<Worker, usize> for WorkerProvider {
    async fn get_rows(&self, range: Range<usize>) -> Result<(Vec<Worker>, Range<usize>), String> {
        let url = self.get_url();
        let Range { start, .. } = range;

        let resp: Vec<Worker> = Request::get(&url)
            .send()
            .await
            .map_err(|e| e.to_string())?
            .json()
            .await
            .map_err(|e| e.to_string())?;
        if start > 0 {
            return Ok((vec![], start..start));
        }
        let r = start..start + resp.len();

        Ok((resp, r))
    }

    async fn row_count(&self) -> Option<usize> {
        let url = self.get_url();
        let resp: Vec<Worker> = Request::get(&url)
            .send()
            .await
            .map_err(|e| e.to_string())
            .ok()?
            .json()
            .await
            .map_err(|e| e.to_string())
            .ok()?;
        Some(resp.len())
    }

    fn set_sorting(&mut self, sorting: &VecDeque<(usize, ColumnSort)>) {
        self.sorting = sorting.clone();
    }

    fn track(&self) {
        if let Some(q) = self.queue {
            q.track()
        }
    }
}