better charts
This commit is contained in:
@@ -8,6 +8,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// here makes the root common crate usable by TUI and Tauri alike.
|
||||
.type_attribute(".komp_ac.accounting", serde)
|
||||
.type_attribute(".komp_ac.analytics", serde)
|
||||
.field_attribute(".komp_ac.analytics.ReportDashboardFilter.primary", "#[serde(default)]")
|
||||
.type_attribute(".komp_ac.auth", serde)
|
||||
.type_attribute(".komp_ac.common", serde)
|
||||
.type_attribute(".komp_ac.document_data", serde)
|
||||
|
||||
@@ -281,6 +281,28 @@ message ReportFilterTarget {
|
||||
message ReportDashboardFilter {
|
||||
ReportParameter parameter = 1;
|
||||
repeated ReportFilterTarget targets = 2;
|
||||
bool primary = 3;
|
||||
}
|
||||
|
||||
enum ReportPeriodBoundary {
|
||||
REPORT_PERIOD_BOUNDARY_UNSPECIFIED = 0;
|
||||
REPORT_PERIOD_BOUNDARY_INCLUSIVE = 1;
|
||||
REPORT_PERIOD_BOUNDARY_EXCLUSIVE = 2;
|
||||
}
|
||||
|
||||
message ReportDateRange {
|
||||
string start_filter = 1;
|
||||
string end_filter = 2;
|
||||
ReportPeriodBoundary end_boundary = 3;
|
||||
}
|
||||
|
||||
message ReportPeriod {
|
||||
string date_basis = 1;
|
||||
oneof selection {
|
||||
ReportDateRange date_range = 2;
|
||||
string accounting_period_filter = 3;
|
||||
string as_of_filter = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message ReportActionBinding {
|
||||
@@ -353,6 +375,7 @@ message ReportDashboardDefinition {
|
||||
repeated ReportGrant grants = 5;
|
||||
uint32 refresh_seconds = 6;
|
||||
repeated ReportDatasetVersionRef dataset_versions = 7;
|
||||
ReportPeriod period = 8;
|
||||
}
|
||||
|
||||
message ReportDatasetVersionRef {
|
||||
|
||||
Binary file not shown.
@@ -252,6 +252,40 @@ pub struct ReportDashboardFilter {
|
||||
pub parameter: ::core::option::Option<ReportParameter>,
|
||||
#[prost(message, repeated, tag = "2")]
|
||||
pub targets: ::prost::alloc::vec::Vec<ReportFilterTarget>,
|
||||
#[prost(bool, tag = "3")]
|
||||
#[serde(default)]
|
||||
pub primary: bool,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct ReportDateRange {
|
||||
#[prost(string, tag = "1")]
|
||||
pub start_filter: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "2")]
|
||||
pub end_filter: ::prost::alloc::string::String,
|
||||
#[prost(enumeration = "ReportPeriodBoundary", tag = "3")]
|
||||
pub end_boundary: i32,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct ReportPeriod {
|
||||
#[prost(string, tag = "1")]
|
||||
pub date_basis: ::prost::alloc::string::String,
|
||||
#[prost(oneof = "report_period::Selection", tags = "2, 3, 4")]
|
||||
pub selection: ::core::option::Option<report_period::Selection>,
|
||||
}
|
||||
/// Nested message and enum types in `ReportPeriod`.
|
||||
pub mod report_period {
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)]
|
||||
pub enum Selection {
|
||||
#[prost(message, tag = "2")]
|
||||
DateRange(super::ReportDateRange),
|
||||
#[prost(string, tag = "3")]
|
||||
AccountingPeriodFilter(::prost::alloc::string::String),
|
||||
#[prost(string, tag = "4")]
|
||||
AsOfFilter(::prost::alloc::string::String),
|
||||
}
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
@@ -390,6 +424,8 @@ pub struct ReportDashboardDefinition {
|
||||
pub refresh_seconds: u32,
|
||||
#[prost(message, repeated, tag = "7")]
|
||||
pub dataset_versions: ::prost::alloc::vec::Vec<ReportDatasetVersionRef>,
|
||||
#[prost(message, optional, tag = "8")]
|
||||
pub period: ::core::option::Option<ReportPeriod>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
@@ -1085,6 +1121,36 @@ impl ReportExecutionPurpose {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum ReportPeriodBoundary {
|
||||
Unspecified = 0,
|
||||
Inclusive = 1,
|
||||
Exclusive = 2,
|
||||
}
|
||||
impl ReportPeriodBoundary {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Unspecified => "REPORT_PERIOD_BOUNDARY_UNSPECIFIED",
|
||||
Self::Inclusive => "REPORT_PERIOD_BOUNDARY_INCLUSIVE",
|
||||
Self::Exclusive => "REPORT_PERIOD_BOUNDARY_EXCLUSIVE",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"REPORT_PERIOD_BOUNDARY_UNSPECIFIED" => Some(Self::Unspecified),
|
||||
"REPORT_PERIOD_BOUNDARY_INCLUSIVE" => Some(Self::Inclusive),
|
||||
"REPORT_PERIOD_BOUNDARY_EXCLUSIVE" => Some(Self::Exclusive),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Generated client implementations.
|
||||
pub mod analytics_service_client {
|
||||
#![allow(
|
||||
|
||||
@@ -263,6 +263,33 @@ fn validate_dashboard(dashboard: &ReportDashboardDefinition) -> Result<(), Strin
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(period) = &dashboard.period {
|
||||
nonempty(&period.date_basis, "Period date basis", 160)?;
|
||||
let parameter = |key: &str, kind: ReportDataType| -> Result<(), String> {
|
||||
let parameter = dashboard.filters.iter().filter_map(|filter| filter.parameter.as_ref())
|
||||
.find(|parameter| parameter.key == key).ok_or("Period refers to an unknown filter")?;
|
||||
let actual_kind: ReportDataType = enum_value(parameter.data_type, "period filter type")?;
|
||||
if parameter.multiple || actual_kind != kind {
|
||||
return Err("Period filters must have the declared single-value type".into());
|
||||
}
|
||||
if !parameter.choices.is_empty() || parameter.lookup.is_some() {
|
||||
return Err("Period filters use the period selector instead of custom choices".into());
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
match period.selection.as_ref().ok_or("A period selection is required")? {
|
||||
report_period::Selection::DateRange(range) => {
|
||||
parameter(&range.start_filter, ReportDataType::Date)?;
|
||||
parameter(&range.end_filter, ReportDataType::Date)?;
|
||||
if range.start_filter == range.end_filter {
|
||||
return Err("A period needs distinct start and end filters".into());
|
||||
}
|
||||
let _: ReportPeriodBoundary = enum_value(range.end_boundary, "period end boundary")?;
|
||||
}
|
||||
report_period::Selection::AccountingPeriodFilter(key) => parameter(key, ReportDataType::Integer)?,
|
||||
report_period::Selection::AsOfFilter(key) => parameter(key, ReportDataType::Date)?,
|
||||
}
|
||||
}
|
||||
let mut panels = HashSet::new();
|
||||
for panel in &dashboard.panels {
|
||||
nonempty(&panel.id, "Panel ID", 64)?;
|
||||
|
||||
Reference in New Issue
Block a user