diff --git a/proto/gen/rill/runtime/v1/resources.pb.go b/proto/gen/rill/runtime/v1/resources.pb.go
index 86c1cf5cfe3e..2b821bea6329 100644
--- a/proto/gen/rill/runtime/v1/resources.pb.go
+++ b/proto/gen/rill/runtime/v1/resources.pb.go
@@ -2685,28 +2685,29 @@ type ExplorePreset struct {
Measures []string `protobuf:"bytes,4,rep,name=measures,proto3" json:"measures,omitempty"`
// Dynamic selector for `measures`. Will be processed during validation, so it will always be empty in `state.valid_spec`.
MeasuresSelector *FieldSelector `protobuf:"bytes,10,opt,name=measures_selector,json=measuresSelector,proto3" json:"measures_selector,omitempty"`
+ Where *Expression `protobuf:"bytes,25,opt,name=where,proto3,oneof" json:"where,omitempty"`
// Time range for the explore.
// It corresponds to the `range` property of the explore's `time_ranges`.
// If not found in `time_ranges`, it should be added to the list.
- TimeRange string `protobuf:"bytes,6,opt,name=time_range,json=timeRange,proto3" json:"time_range,omitempty"`
- Timezone string `protobuf:"bytes,11,opt,name=timezone,proto3" json:"timezone,omitempty"`
- TimeGrain string `protobuf:"bytes,12,opt,name=time_grain,json=timeGrain,proto3" json:"time_grain,omitempty"`
+ TimeRange *string `protobuf:"bytes,6,opt,name=time_range,json=timeRange,proto3,oneof" json:"time_range,omitempty"`
+ Timezone *string `protobuf:"bytes,11,opt,name=timezone,proto3,oneof" json:"timezone,omitempty"`
+ TimeGrain *string `protobuf:"bytes,12,opt,name=time_grain,json=timeGrain,proto3,oneof" json:"time_grain,omitempty"`
// Comparison mode.
ComparisonMode ExploreComparisonMode `protobuf:"varint,7,opt,name=comparison_mode,json=comparisonMode,proto3,enum=rill.runtime.v1.ExploreComparisonMode" json:"comparison_mode,omitempty"`
CompareTimeRange *string `protobuf:"bytes,13,opt,name=compare_time_range,json=compareTimeRange,proto3,oneof" json:"compare_time_range,omitempty"`
// If comparison_mode is EXPLORE_COMPARISON_MODE_DIMENSION, this indicates the dimension to use.
- ComparisonDimension string `protobuf:"bytes,8,opt,name=comparison_dimension,json=comparisonDimension,proto3" json:"comparison_dimension,omitempty"`
- View ExploreWebView `protobuf:"varint,14,opt,name=view,proto3,enum=rill.runtime.v1.ExploreWebView" json:"view,omitempty"`
- OverviewSortBy string `protobuf:"bytes,15,opt,name=overview_sort_by,json=overviewSortBy,proto3" json:"overview_sort_by,omitempty"`
- OverviewSortAsc bool `protobuf:"varint,16,opt,name=overview_sort_asc,json=overviewSortAsc,proto3" json:"overview_sort_asc,omitempty"`
- OverviewExpandedDimension string `protobuf:"bytes,17,opt,name=overview_expanded_dimension,json=overviewExpandedDimension,proto3" json:"overview_expanded_dimension,omitempty"`
- TimeDimensionMeasure string `protobuf:"bytes,18,opt,name=time_dimension_measure,json=timeDimensionMeasure,proto3" json:"time_dimension_measure,omitempty"`
- TimeDimensionChartType string `protobuf:"bytes,19,opt,name=time_dimension_chart_type,json=timeDimensionChartType,proto3" json:"time_dimension_chart_type,omitempty"`
- TimeDimensionPin bool `protobuf:"varint,20,opt,name=time_dimension_pin,json=timeDimensionPin,proto3" json:"time_dimension_pin,omitempty"`
- PivotRows []string `protobuf:"bytes,21,rep,name=pivot_rows,json=pivotRows,proto3" json:"pivot_rows,omitempty"`
- PivotCols []string `protobuf:"bytes,22,rep,name=pivot_cols,json=pivotCols,proto3" json:"pivot_cols,omitempty"`
- PivotSortBy string `protobuf:"bytes,23,opt,name=pivot_sort_by,json=pivotSortBy,proto3" json:"pivot_sort_by,omitempty"`
- PivotSortAsc bool `protobuf:"varint,24,opt,name=pivot_sort_asc,json=pivotSortAsc,proto3" json:"pivot_sort_asc,omitempty"`
+ ComparisonDimension *string `protobuf:"bytes,8,opt,name=comparison_dimension,json=comparisonDimension,proto3,oneof" json:"comparison_dimension,omitempty"`
+ View *ExploreWebView `protobuf:"varint,14,opt,name=view,proto3,enum=rill.runtime.v1.ExploreWebView,oneof" json:"view,omitempty"`
+ OverviewSortBy *string `protobuf:"bytes,15,opt,name=overview_sort_by,json=overviewSortBy,proto3,oneof" json:"overview_sort_by,omitempty"`
+ OverviewSortAsc *bool `protobuf:"varint,16,opt,name=overview_sort_asc,json=overviewSortAsc,proto3,oneof" json:"overview_sort_asc,omitempty"`
+ OverviewExpandedDimension *string `protobuf:"bytes,17,opt,name=overview_expanded_dimension,json=overviewExpandedDimension,proto3,oneof" json:"overview_expanded_dimension,omitempty"`
+ TimeDimensionMeasure *string `protobuf:"bytes,18,opt,name=time_dimension_measure,json=timeDimensionMeasure,proto3,oneof" json:"time_dimension_measure,omitempty"`
+ TimeDimensionChartType *string `protobuf:"bytes,19,opt,name=time_dimension_chart_type,json=timeDimensionChartType,proto3,oneof" json:"time_dimension_chart_type,omitempty"`
+ TimeDimensionPin *bool `protobuf:"varint,20,opt,name=time_dimension_pin,json=timeDimensionPin,proto3,oneof" json:"time_dimension_pin,omitempty"`
+ PivotRows []string `protobuf:"bytes,21,rep,name=pivot_rows,json=pivotRows,proto3" json:"pivot_rows,omitempty"`
+ PivotCols []string `protobuf:"bytes,22,rep,name=pivot_cols,json=pivotCols,proto3" json:"pivot_cols,omitempty"`
+ PivotSortBy *string `protobuf:"bytes,23,opt,name=pivot_sort_by,json=pivotSortBy,proto3,oneof" json:"pivot_sort_by,omitempty"`
+ PivotSortAsc *bool `protobuf:"varint,24,opt,name=pivot_sort_asc,json=pivotSortAsc,proto3,oneof" json:"pivot_sort_asc,omitempty"`
}
func (x *ExplorePreset) Reset() {
@@ -2769,23 +2770,30 @@ func (x *ExplorePreset) GetMeasuresSelector() *FieldSelector {
return nil
}
-func (x *ExplorePreset) GetTimeRange() string {
+func (x *ExplorePreset) GetWhere() *Expression {
if x != nil {
- return x.TimeRange
+ return x.Where
+ }
+ return nil
+}
+
+func (x *ExplorePreset) GetTimeRange() string {
+ if x != nil && x.TimeRange != nil {
+ return *x.TimeRange
}
return ""
}
func (x *ExplorePreset) GetTimezone() string {
- if x != nil {
- return x.Timezone
+ if x != nil && x.Timezone != nil {
+ return *x.Timezone
}
return ""
}
func (x *ExplorePreset) GetTimeGrain() string {
- if x != nil {
- return x.TimeGrain
+ if x != nil && x.TimeGrain != nil {
+ return *x.TimeGrain
}
return ""
}
@@ -2805,57 +2813,57 @@ func (x *ExplorePreset) GetCompareTimeRange() string {
}
func (x *ExplorePreset) GetComparisonDimension() string {
- if x != nil {
- return x.ComparisonDimension
+ if x != nil && x.ComparisonDimension != nil {
+ return *x.ComparisonDimension
}
return ""
}
func (x *ExplorePreset) GetView() ExploreWebView {
- if x != nil {
- return x.View
+ if x != nil && x.View != nil {
+ return *x.View
}
return ExploreWebView_EXPLORE_ACTIVE_PAGE_UNSPECIFIED
}
func (x *ExplorePreset) GetOverviewSortBy() string {
- if x != nil {
- return x.OverviewSortBy
+ if x != nil && x.OverviewSortBy != nil {
+ return *x.OverviewSortBy
}
return ""
}
func (x *ExplorePreset) GetOverviewSortAsc() bool {
- if x != nil {
- return x.OverviewSortAsc
+ if x != nil && x.OverviewSortAsc != nil {
+ return *x.OverviewSortAsc
}
return false
}
func (x *ExplorePreset) GetOverviewExpandedDimension() string {
- if x != nil {
- return x.OverviewExpandedDimension
+ if x != nil && x.OverviewExpandedDimension != nil {
+ return *x.OverviewExpandedDimension
}
return ""
}
func (x *ExplorePreset) GetTimeDimensionMeasure() string {
- if x != nil {
- return x.TimeDimensionMeasure
+ if x != nil && x.TimeDimensionMeasure != nil {
+ return *x.TimeDimensionMeasure
}
return ""
}
func (x *ExplorePreset) GetTimeDimensionChartType() string {
- if x != nil {
- return x.TimeDimensionChartType
+ if x != nil && x.TimeDimensionChartType != nil {
+ return *x.TimeDimensionChartType
}
return ""
}
func (x *ExplorePreset) GetTimeDimensionPin() bool {
- if x != nil {
- return x.TimeDimensionPin
+ if x != nil && x.TimeDimensionPin != nil {
+ return *x.TimeDimensionPin
}
return false
}
@@ -2875,15 +2883,15 @@ func (x *ExplorePreset) GetPivotCols() []string {
}
func (x *ExplorePreset) GetPivotSortBy() string {
- if x != nil {
- return x.PivotSortBy
+ if x != nil && x.PivotSortBy != nil {
+ return *x.PivotSortBy
}
return ""
}
func (x *ExplorePreset) GetPivotSortAsc() bool {
- if x != nil {
- return x.PivotSortAsc
+ if x != nil && x.PivotSortAsc != nil {
+ return *x.PivotSortAsc
}
return false
}
@@ -7245,7 +7253,7 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{
0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14,
0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72,
- 0x61, 0x6e, 0x67, 0x65, 0x22, 0x83, 0x08, 0x0a, 0x0d, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65,
+ 0x61, 0x6e, 0x67, 0x65, 0x22, 0x93, 0x0b, 0x0a, 0x0d, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65,
0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x69, 0x6d, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x13, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
@@ -7260,56 +7268,81 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{
0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x10,
0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
- 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x06,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12,
- 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74,
- 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x09, 0x74, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x12, 0x4f, 0x0a, 0x0f, 0x63, 0x6f,
- 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20,
- 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
- 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d,
- 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d,
- 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, 0x12, 0x63,
- 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67,
- 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x61,
- 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x31,
- 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x6d,
- 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f,
- 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
- 0x6e, 0x12, 0x33, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32,
- 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
- 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x57, 0x65, 0x62, 0x56, 0x69, 0x65, 0x77,
- 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69,
- 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79,
- 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72,
- 0x74, 0x5f, 0x61, 0x73, 0x63, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x76, 0x65,
- 0x72, 0x76, 0x69, 0x65, 0x77, 0x53, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x63, 0x12, 0x3e, 0x0a, 0x1b,
- 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65,
- 0x64, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x19, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x45, 0x78, 0x70, 0x61, 0x6e,
- 0x64, 0x65, 0x64, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16,
+ 0x12, 0x36, 0x0a, 0x05, 0x77, 0x68, 0x65, 0x72, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05,
+ 0x77, 0x68, 0x65, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09,
+ 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08,
+ 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02,
+ 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a,
+ 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28,
+ 0x09, 0x48, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x88, 0x01,
+ 0x01, 0x12, 0x4f, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x72, 0x69, 0x6c,
+ 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70,
+ 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f,
+ 0x64, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f,
+ 0x64, 0x65, 0x12, 0x31, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x69,
+ 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04,
+ 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e,
+ 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69,
+ 0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20,
+ 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f,
+ 0x6e, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a,
+ 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, 0x69,
+ 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78,
+ 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x57, 0x65, 0x62, 0x56, 0x69, 0x65, 0x77, 0x48, 0x06, 0x52, 0x04,
+ 0x76, 0x69, 0x65, 0x77, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x76,
+ 0x69, 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28,
+ 0x09, 0x48, 0x07, 0x52, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x53, 0x6f, 0x72,
+ 0x74, 0x42, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69,
+ 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x61, 0x73, 0x63, 0x18, 0x10, 0x20, 0x01, 0x28,
+ 0x08, 0x48, 0x08, 0x52, 0x0f, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x53, 0x6f, 0x72,
+ 0x74, 0x41, 0x73, 0x63, 0x88, 0x01, 0x01, 0x12, 0x43, 0x0a, 0x1b, 0x6f, 0x76, 0x65, 0x72, 0x76,
+ 0x69, 0x65, 0x77, 0x5f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x6d,
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x48, 0x09, 0x52, 0x19,
+ 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x64,
+ 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16,
0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d,
- 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x74, 0x69,
- 0x6d, 0x65, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75,
- 0x72, 0x65, 0x12, 0x39, 0x0a, 0x19, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e,
- 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
- 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x6d, 0x65, 0x6e,
- 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a,
- 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
- 0x70, 0x69, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x44,
- 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70,
- 0x69, 0x76, 0x6f, 0x74, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x09, 0x52,
- 0x09, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x69,
- 0x76, 0x6f, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
- 0x70, 0x69, 0x76, 0x6f, 0x74, 0x43, 0x6f, 0x6c, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x69, 0x76,
- 0x6f, 0x74, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0b, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x24, 0x0a,
- 0x0e, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x61, 0x73, 0x63, 0x18,
- 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x6f, 0x72, 0x74,
- 0x41, 0x73, 0x63, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x5f,
- 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xca, 0x01, 0x0a, 0x0d, 0x46,
+ 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0a, 0x52, 0x14,
+ 0x74, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x61,
+ 0x73, 0x75, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x19, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+ 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0b, 0x52, 0x16, 0x74, 0x69,
+ 0x6d, 0x65, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x72, 0x74,
+ 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+ 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x69, 0x6e, 0x18, 0x14, 0x20,
+ 0x01, 0x28, 0x08, 0x48, 0x0c, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x6d, 0x65, 0x6e,
+ 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x69, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x69,
+ 0x76, 0x6f, 0x74, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
+ 0x70, 0x69, 0x76, 0x6f, 0x74, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x69, 0x76,
+ 0x6f, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70,
+ 0x69, 0x76, 0x6f, 0x74, 0x43, 0x6f, 0x6c, 0x73, 0x12, 0x27, 0x0a, 0x0d, 0x70, 0x69, 0x76, 0x6f,
+ 0x74, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x48,
+ 0x0d, 0x52, 0x0b, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x88, 0x01,
+ 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f,
+ 0x61, 0x73, 0x63, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x48, 0x0e, 0x52, 0x0c, 0x70, 0x69, 0x76,
+ 0x6f, 0x74, 0x53, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x63, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06,
+ 0x5f, 0x77, 0x68, 0x65, 0x72, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f,
+ 0x6e, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69,
+ 0x6e, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x69,
+ 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x63, 0x6f, 0x6d,
+ 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+ 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x6f,
+ 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x42,
+ 0x14, 0x0a, 0x12, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x73, 0x6f, 0x72,
+ 0x74, 0x5f, 0x61, 0x73, 0x63, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69,
+ 0x65, 0x77, 0x5f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x6d, 0x65,
+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64,
+ 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65,
+ 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x15,
+ 0x0a, 0x13, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x70, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x5f,
+ 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x70, 0x69, 0x76, 0x6f,
+ 0x74, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x61, 0x73, 0x63, 0x22, 0xca, 0x01, 0x0a, 0x0d, 0x46,
0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06,
0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x6e,
0x76, 0x65, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
@@ -8097,92 +8130,93 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{
30, // 68: rill.runtime.v1.ExploreTimeRange.comparison_time_ranges:type_name -> rill.runtime.v1.ExploreComparisonTimeRange
32, // 69: rill.runtime.v1.ExplorePreset.dimensions_selector:type_name -> rill.runtime.v1.FieldSelector
32, // 70: rill.runtime.v1.ExplorePreset.measures_selector:type_name -> rill.runtime.v1.FieldSelector
- 1, // 71: rill.runtime.v1.ExplorePreset.comparison_mode:type_name -> rill.runtime.v1.ExploreComparisonMode
- 2, // 72: rill.runtime.v1.ExplorePreset.view:type_name -> rill.runtime.v1.ExploreWebView
- 33, // 73: rill.runtime.v1.FieldSelector.fields:type_name -> rill.runtime.v1.StringListValue
- 35, // 74: rill.runtime.v1.Migration.spec:type_name -> rill.runtime.v1.MigrationSpec
- 36, // 75: rill.runtime.v1.Migration.state:type_name -> rill.runtime.v1.MigrationState
- 38, // 76: rill.runtime.v1.Report.spec:type_name -> rill.runtime.v1.ReportSpec
- 39, // 77: rill.runtime.v1.Report.state:type_name -> rill.runtime.v1.ReportState
- 72, // 78: rill.runtime.v1.ReportSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule
- 96, // 79: rill.runtime.v1.ReportSpec.export_format:type_name -> rill.runtime.v1.ExportFormat
- 43, // 80: rill.runtime.v1.ReportSpec.notifiers:type_name -> rill.runtime.v1.Notifier
- 87, // 81: rill.runtime.v1.ReportSpec.annotations:type_name -> rill.runtime.v1.ReportSpec.AnnotationsEntry
- 91, // 82: rill.runtime.v1.ReportState.next_run_on:type_name -> google.protobuf.Timestamp
- 40, // 83: rill.runtime.v1.ReportState.current_execution:type_name -> rill.runtime.v1.ReportExecution
- 40, // 84: rill.runtime.v1.ReportState.execution_history:type_name -> rill.runtime.v1.ReportExecution
- 91, // 85: rill.runtime.v1.ReportExecution.report_time:type_name -> google.protobuf.Timestamp
- 91, // 86: rill.runtime.v1.ReportExecution.started_on:type_name -> google.protobuf.Timestamp
- 91, // 87: rill.runtime.v1.ReportExecution.finished_on:type_name -> google.protobuf.Timestamp
- 42, // 88: rill.runtime.v1.Alert.spec:type_name -> rill.runtime.v1.AlertSpec
- 44, // 89: rill.runtime.v1.Alert.state:type_name -> rill.runtime.v1.AlertState
- 72, // 90: rill.runtime.v1.AlertSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule
- 92, // 91: rill.runtime.v1.AlertSpec.resolver_properties:type_name -> google.protobuf.Struct
- 92, // 92: rill.runtime.v1.AlertSpec.query_for_attributes:type_name -> google.protobuf.Struct
- 43, // 93: rill.runtime.v1.AlertSpec.notifiers:type_name -> rill.runtime.v1.Notifier
- 88, // 94: rill.runtime.v1.AlertSpec.annotations:type_name -> rill.runtime.v1.AlertSpec.AnnotationsEntry
- 92, // 95: rill.runtime.v1.Notifier.properties:type_name -> google.protobuf.Struct
- 91, // 96: rill.runtime.v1.AlertState.next_run_on:type_name -> google.protobuf.Timestamp
- 45, // 97: rill.runtime.v1.AlertState.current_execution:type_name -> rill.runtime.v1.AlertExecution
- 45, // 98: rill.runtime.v1.AlertState.execution_history:type_name -> rill.runtime.v1.AlertExecution
- 46, // 99: rill.runtime.v1.AlertExecution.result:type_name -> rill.runtime.v1.AssertionResult
- 91, // 100: rill.runtime.v1.AlertExecution.execution_time:type_name -> google.protobuf.Timestamp
- 91, // 101: rill.runtime.v1.AlertExecution.started_on:type_name -> google.protobuf.Timestamp
- 91, // 102: rill.runtime.v1.AlertExecution.finished_on:type_name -> google.protobuf.Timestamp
- 91, // 103: rill.runtime.v1.AlertExecution.suppressed_since:type_name -> google.protobuf.Timestamp
- 3, // 104: rill.runtime.v1.AssertionResult.status:type_name -> rill.runtime.v1.AssertionStatus
- 92, // 105: rill.runtime.v1.AssertionResult.fail_row:type_name -> google.protobuf.Struct
- 48, // 106: rill.runtime.v1.PullTrigger.spec:type_name -> rill.runtime.v1.PullTriggerSpec
- 49, // 107: rill.runtime.v1.PullTrigger.state:type_name -> rill.runtime.v1.PullTriggerState
- 51, // 108: rill.runtime.v1.RefreshTrigger.spec:type_name -> rill.runtime.v1.RefreshTriggerSpec
- 52, // 109: rill.runtime.v1.RefreshTrigger.state:type_name -> rill.runtime.v1.RefreshTriggerState
- 9, // 110: rill.runtime.v1.RefreshTriggerSpec.resources:type_name -> rill.runtime.v1.ResourceName
- 53, // 111: rill.runtime.v1.RefreshTriggerSpec.models:type_name -> rill.runtime.v1.RefreshModelTrigger
- 55, // 112: rill.runtime.v1.BucketPlanner.spec:type_name -> rill.runtime.v1.BucketPlannerSpec
- 56, // 113: rill.runtime.v1.BucketPlanner.state:type_name -> rill.runtime.v1.BucketPlannerState
- 57, // 114: rill.runtime.v1.BucketPlannerSpec.extract_policy:type_name -> rill.runtime.v1.BucketExtractPolicy
- 6, // 115: rill.runtime.v1.BucketExtractPolicy.rows_strategy:type_name -> rill.runtime.v1.BucketExtractPolicy.Strategy
- 6, // 116: rill.runtime.v1.BucketExtractPolicy.files_strategy:type_name -> rill.runtime.v1.BucketExtractPolicy.Strategy
- 59, // 117: rill.runtime.v1.Theme.spec:type_name -> rill.runtime.v1.ThemeSpec
- 60, // 118: rill.runtime.v1.Theme.state:type_name -> rill.runtime.v1.ThemeState
- 97, // 119: rill.runtime.v1.ThemeSpec.primary_color:type_name -> rill.runtime.v1.Color
- 97, // 120: rill.runtime.v1.ThemeSpec.secondary_color:type_name -> rill.runtime.v1.Color
- 62, // 121: rill.runtime.v1.Component.spec:type_name -> rill.runtime.v1.ComponentSpec
- 63, // 122: rill.runtime.v1.Component.state:type_name -> rill.runtime.v1.ComponentState
- 92, // 123: rill.runtime.v1.ComponentSpec.resolver_properties:type_name -> google.protobuf.Struct
- 92, // 124: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct
- 64, // 125: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable
- 64, // 126: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable
- 62, // 127: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec
- 98, // 128: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value
- 66, // 129: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec
- 67, // 130: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState
- 64, // 131: rill.runtime.v1.CanvasSpec.variables:type_name -> rill.runtime.v1.ComponentVariable
- 68, // 132: rill.runtime.v1.CanvasSpec.items:type_name -> rill.runtime.v1.CanvasItem
- 21, // 133: rill.runtime.v1.CanvasSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule
- 66, // 134: rill.runtime.v1.CanvasState.valid_spec:type_name -> rill.runtime.v1.CanvasSpec
- 70, // 135: rill.runtime.v1.API.spec:type_name -> rill.runtime.v1.APISpec
- 71, // 136: rill.runtime.v1.API.state:type_name -> rill.runtime.v1.APIState
- 92, // 137: rill.runtime.v1.APISpec.resolver_properties:type_name -> google.protobuf.Struct
- 92, // 138: rill.runtime.v1.APISpec.openapi_parameters:type_name -> google.protobuf.Struct
- 92, // 139: rill.runtime.v1.APISpec.openapi_response_schema:type_name -> google.protobuf.Struct
- 77, // 140: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation
- 89, // 141: rill.runtime.v1.ConnectorSpec.properties:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesEntry
- 90, // 142: rill.runtime.v1.ConnectorSpec.properties_from_variables:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesFromVariablesEntry
- 78, // 143: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec
- 79, // 144: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState
- 94, // 145: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain
- 82, // 146: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
- 4, // 147: rill.runtime.v1.MetricsViewSpec.MeasureV2.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType
- 83, // 148: rill.runtime.v1.MetricsViewSpec.MeasureV2.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow
- 82, // 149: rill.runtime.v1.MetricsViewSpec.MeasureV2.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
- 82, // 150: rill.runtime.v1.MetricsViewSpec.MeasureV2.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
- 85, // 151: rill.runtime.v1.MetricsViewSpec.AvailableTimeRange.comparison_offsets:type_name -> rill.runtime.v1.MetricsViewSpec.AvailableComparisonOffset
- 152, // [152:152] is the sub-list for method output_type
- 152, // [152:152] is the sub-list for method input_type
- 152, // [152:152] is the sub-list for extension type_name
- 152, // [152:152] is the sub-list for extension extendee
- 0, // [0:152] is the sub-list for field type_name
+ 95, // 71: rill.runtime.v1.ExplorePreset.where:type_name -> rill.runtime.v1.Expression
+ 1, // 72: rill.runtime.v1.ExplorePreset.comparison_mode:type_name -> rill.runtime.v1.ExploreComparisonMode
+ 2, // 73: rill.runtime.v1.ExplorePreset.view:type_name -> rill.runtime.v1.ExploreWebView
+ 33, // 74: rill.runtime.v1.FieldSelector.fields:type_name -> rill.runtime.v1.StringListValue
+ 35, // 75: rill.runtime.v1.Migration.spec:type_name -> rill.runtime.v1.MigrationSpec
+ 36, // 76: rill.runtime.v1.Migration.state:type_name -> rill.runtime.v1.MigrationState
+ 38, // 77: rill.runtime.v1.Report.spec:type_name -> rill.runtime.v1.ReportSpec
+ 39, // 78: rill.runtime.v1.Report.state:type_name -> rill.runtime.v1.ReportState
+ 72, // 79: rill.runtime.v1.ReportSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule
+ 96, // 80: rill.runtime.v1.ReportSpec.export_format:type_name -> rill.runtime.v1.ExportFormat
+ 43, // 81: rill.runtime.v1.ReportSpec.notifiers:type_name -> rill.runtime.v1.Notifier
+ 87, // 82: rill.runtime.v1.ReportSpec.annotations:type_name -> rill.runtime.v1.ReportSpec.AnnotationsEntry
+ 91, // 83: rill.runtime.v1.ReportState.next_run_on:type_name -> google.protobuf.Timestamp
+ 40, // 84: rill.runtime.v1.ReportState.current_execution:type_name -> rill.runtime.v1.ReportExecution
+ 40, // 85: rill.runtime.v1.ReportState.execution_history:type_name -> rill.runtime.v1.ReportExecution
+ 91, // 86: rill.runtime.v1.ReportExecution.report_time:type_name -> google.protobuf.Timestamp
+ 91, // 87: rill.runtime.v1.ReportExecution.started_on:type_name -> google.protobuf.Timestamp
+ 91, // 88: rill.runtime.v1.ReportExecution.finished_on:type_name -> google.protobuf.Timestamp
+ 42, // 89: rill.runtime.v1.Alert.spec:type_name -> rill.runtime.v1.AlertSpec
+ 44, // 90: rill.runtime.v1.Alert.state:type_name -> rill.runtime.v1.AlertState
+ 72, // 91: rill.runtime.v1.AlertSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule
+ 92, // 92: rill.runtime.v1.AlertSpec.resolver_properties:type_name -> google.protobuf.Struct
+ 92, // 93: rill.runtime.v1.AlertSpec.query_for_attributes:type_name -> google.protobuf.Struct
+ 43, // 94: rill.runtime.v1.AlertSpec.notifiers:type_name -> rill.runtime.v1.Notifier
+ 88, // 95: rill.runtime.v1.AlertSpec.annotations:type_name -> rill.runtime.v1.AlertSpec.AnnotationsEntry
+ 92, // 96: rill.runtime.v1.Notifier.properties:type_name -> google.protobuf.Struct
+ 91, // 97: rill.runtime.v1.AlertState.next_run_on:type_name -> google.protobuf.Timestamp
+ 45, // 98: rill.runtime.v1.AlertState.current_execution:type_name -> rill.runtime.v1.AlertExecution
+ 45, // 99: rill.runtime.v1.AlertState.execution_history:type_name -> rill.runtime.v1.AlertExecution
+ 46, // 100: rill.runtime.v1.AlertExecution.result:type_name -> rill.runtime.v1.AssertionResult
+ 91, // 101: rill.runtime.v1.AlertExecution.execution_time:type_name -> google.protobuf.Timestamp
+ 91, // 102: rill.runtime.v1.AlertExecution.started_on:type_name -> google.protobuf.Timestamp
+ 91, // 103: rill.runtime.v1.AlertExecution.finished_on:type_name -> google.protobuf.Timestamp
+ 91, // 104: rill.runtime.v1.AlertExecution.suppressed_since:type_name -> google.protobuf.Timestamp
+ 3, // 105: rill.runtime.v1.AssertionResult.status:type_name -> rill.runtime.v1.AssertionStatus
+ 92, // 106: rill.runtime.v1.AssertionResult.fail_row:type_name -> google.protobuf.Struct
+ 48, // 107: rill.runtime.v1.PullTrigger.spec:type_name -> rill.runtime.v1.PullTriggerSpec
+ 49, // 108: rill.runtime.v1.PullTrigger.state:type_name -> rill.runtime.v1.PullTriggerState
+ 51, // 109: rill.runtime.v1.RefreshTrigger.spec:type_name -> rill.runtime.v1.RefreshTriggerSpec
+ 52, // 110: rill.runtime.v1.RefreshTrigger.state:type_name -> rill.runtime.v1.RefreshTriggerState
+ 9, // 111: rill.runtime.v1.RefreshTriggerSpec.resources:type_name -> rill.runtime.v1.ResourceName
+ 53, // 112: rill.runtime.v1.RefreshTriggerSpec.models:type_name -> rill.runtime.v1.RefreshModelTrigger
+ 55, // 113: rill.runtime.v1.BucketPlanner.spec:type_name -> rill.runtime.v1.BucketPlannerSpec
+ 56, // 114: rill.runtime.v1.BucketPlanner.state:type_name -> rill.runtime.v1.BucketPlannerState
+ 57, // 115: rill.runtime.v1.BucketPlannerSpec.extract_policy:type_name -> rill.runtime.v1.BucketExtractPolicy
+ 6, // 116: rill.runtime.v1.BucketExtractPolicy.rows_strategy:type_name -> rill.runtime.v1.BucketExtractPolicy.Strategy
+ 6, // 117: rill.runtime.v1.BucketExtractPolicy.files_strategy:type_name -> rill.runtime.v1.BucketExtractPolicy.Strategy
+ 59, // 118: rill.runtime.v1.Theme.spec:type_name -> rill.runtime.v1.ThemeSpec
+ 60, // 119: rill.runtime.v1.Theme.state:type_name -> rill.runtime.v1.ThemeState
+ 97, // 120: rill.runtime.v1.ThemeSpec.primary_color:type_name -> rill.runtime.v1.Color
+ 97, // 121: rill.runtime.v1.ThemeSpec.secondary_color:type_name -> rill.runtime.v1.Color
+ 62, // 122: rill.runtime.v1.Component.spec:type_name -> rill.runtime.v1.ComponentSpec
+ 63, // 123: rill.runtime.v1.Component.state:type_name -> rill.runtime.v1.ComponentState
+ 92, // 124: rill.runtime.v1.ComponentSpec.resolver_properties:type_name -> google.protobuf.Struct
+ 92, // 125: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct
+ 64, // 126: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable
+ 64, // 127: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable
+ 62, // 128: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec
+ 98, // 129: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value
+ 66, // 130: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec
+ 67, // 131: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState
+ 64, // 132: rill.runtime.v1.CanvasSpec.variables:type_name -> rill.runtime.v1.ComponentVariable
+ 68, // 133: rill.runtime.v1.CanvasSpec.items:type_name -> rill.runtime.v1.CanvasItem
+ 21, // 134: rill.runtime.v1.CanvasSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule
+ 66, // 135: rill.runtime.v1.CanvasState.valid_spec:type_name -> rill.runtime.v1.CanvasSpec
+ 70, // 136: rill.runtime.v1.API.spec:type_name -> rill.runtime.v1.APISpec
+ 71, // 137: rill.runtime.v1.API.state:type_name -> rill.runtime.v1.APIState
+ 92, // 138: rill.runtime.v1.APISpec.resolver_properties:type_name -> google.protobuf.Struct
+ 92, // 139: rill.runtime.v1.APISpec.openapi_parameters:type_name -> google.protobuf.Struct
+ 92, // 140: rill.runtime.v1.APISpec.openapi_response_schema:type_name -> google.protobuf.Struct
+ 77, // 141: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation
+ 89, // 142: rill.runtime.v1.ConnectorSpec.properties:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesEntry
+ 90, // 143: rill.runtime.v1.ConnectorSpec.properties_from_variables:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesFromVariablesEntry
+ 78, // 144: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec
+ 79, // 145: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState
+ 94, // 146: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain
+ 82, // 147: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
+ 4, // 148: rill.runtime.v1.MetricsViewSpec.MeasureV2.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType
+ 83, // 149: rill.runtime.v1.MetricsViewSpec.MeasureV2.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow
+ 82, // 150: rill.runtime.v1.MetricsViewSpec.MeasureV2.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
+ 82, // 151: rill.runtime.v1.MetricsViewSpec.MeasureV2.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector
+ 85, // 152: rill.runtime.v1.MetricsViewSpec.AvailableTimeRange.comparison_offsets:type_name -> rill.runtime.v1.MetricsViewSpec.AvailableComparisonOffset
+ 153, // [153:153] is the sub-list for method output_type
+ 153, // [153:153] is the sub-list for method input_type
+ 153, // [153:153] is the sub-list for extension type_name
+ 153, // [153:153] is the sub-list for extension extendee
+ 0, // [0:153] is the sub-list for field type_name
}
func init() { file_rill_runtime_v1_resources_proto_init() }
diff --git a/proto/gen/rill/runtime/v1/resources.pb.validate.go b/proto/gen/rill/runtime/v1/resources.pb.validate.go
index 41df2efa9f3f..e297e6e2b98b 100644
--- a/proto/gen/rill/runtime/v1/resources.pb.validate.go
+++ b/proto/gen/rill/runtime/v1/resources.pb.validate.go
@@ -4857,36 +4857,95 @@ func (m *ExplorePreset) validate(all bool) error {
}
}
- // no validation rules for TimeRange
+ // no validation rules for ComparisonMode
- // no validation rules for Timezone
+ if m.Where != nil {
- // no validation rules for TimeGrain
+ if all {
+ switch v := interface{}(m.GetWhere()).(type) {
+ case interface{ ValidateAll() error }:
+ if err := v.ValidateAll(); err != nil {
+ errors = append(errors, ExplorePresetValidationError{
+ field: "Where",
+ reason: "embedded message failed validation",
+ cause: err,
+ })
+ }
+ case interface{ Validate() error }:
+ if err := v.Validate(); err != nil {
+ errors = append(errors, ExplorePresetValidationError{
+ field: "Where",
+ reason: "embedded message failed validation",
+ cause: err,
+ })
+ }
+ }
+ } else if v, ok := interface{}(m.GetWhere()).(interface{ Validate() error }); ok {
+ if err := v.Validate(); err != nil {
+ return ExplorePresetValidationError{
+ field: "Where",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
- // no validation rules for ComparisonMode
+ }
+
+ if m.TimeRange != nil {
+ // no validation rules for TimeRange
+ }
+
+ if m.Timezone != nil {
+ // no validation rules for Timezone
+ }
- // no validation rules for ComparisonDimension
+ if m.TimeGrain != nil {
+ // no validation rules for TimeGrain
+ }
+
+ if m.CompareTimeRange != nil {
+ // no validation rules for CompareTimeRange
+ }
- // no validation rules for View
+ if m.ComparisonDimension != nil {
+ // no validation rules for ComparisonDimension
+ }
- // no validation rules for OverviewSortBy
+ if m.View != nil {
+ // no validation rules for View
+ }
- // no validation rules for OverviewSortAsc
+ if m.OverviewSortBy != nil {
+ // no validation rules for OverviewSortBy
+ }
- // no validation rules for OverviewExpandedDimension
+ if m.OverviewSortAsc != nil {
+ // no validation rules for OverviewSortAsc
+ }
- // no validation rules for TimeDimensionMeasure
+ if m.OverviewExpandedDimension != nil {
+ // no validation rules for OverviewExpandedDimension
+ }
- // no validation rules for TimeDimensionChartType
+ if m.TimeDimensionMeasure != nil {
+ // no validation rules for TimeDimensionMeasure
+ }
- // no validation rules for TimeDimensionPin
+ if m.TimeDimensionChartType != nil {
+ // no validation rules for TimeDimensionChartType
+ }
- // no validation rules for PivotSortBy
+ if m.TimeDimensionPin != nil {
+ // no validation rules for TimeDimensionPin
+ }
- // no validation rules for PivotSortAsc
+ if m.PivotSortBy != nil {
+ // no validation rules for PivotSortBy
+ }
- if m.CompareTimeRange != nil {
- // no validation rules for CompareTimeRange
+ if m.PivotSortAsc != nil {
+ // no validation rules for PivotSortAsc
}
if len(errors) > 0 {
diff --git a/proto/gen/rill/runtime/v1/runtime.swagger.yaml b/proto/gen/rill/runtime/v1/runtime.swagger.yaml
index 15107d513a50..af72347b0b46 100644
--- a/proto/gen/rill/runtime/v1/runtime.swagger.yaml
+++ b/proto/gen/rill/runtime/v1/runtime.swagger.yaml
@@ -3999,6 +3999,8 @@ definitions:
measuresSelector:
$ref: '#/definitions/v1FieldSelector'
description: Dynamic selector for `measures`. Will be processed during validation, so it will always be empty in `state.valid_spec`.
+ where:
+ $ref: '#/definitions/v1Expression'
timeRange:
type: string
description: |-
diff --git a/proto/rill/runtime/v1/resources.proto b/proto/rill/runtime/v1/resources.proto
index fa000e0cfa14..9c734719a9c4 100644
--- a/proto/rill/runtime/v1/resources.proto
+++ b/proto/rill/runtime/v1/resources.proto
@@ -382,33 +382,35 @@ message ExplorePreset {
// Dynamic selector for `measures`. Will be processed during validation, so it will always be empty in `state.valid_spec`.
FieldSelector measures_selector = 10;
+ optional Expression where = 25;
+
// Time range for the explore.
// It corresponds to the `range` property of the explore's `time_ranges`.
// If not found in `time_ranges`, it should be added to the list.
- string time_range = 6;
- string timezone = 11;
- string time_grain = 12;
+ optional string time_range = 6;
+ optional string timezone = 11;
+ optional string time_grain = 12;
// Comparison mode.
ExploreComparisonMode comparison_mode = 7;
optional string compare_time_range = 13;
// If comparison_mode is EXPLORE_COMPARISON_MODE_DIMENSION, this indicates the dimension to use.
- string comparison_dimension = 8;
+ optional string comparison_dimension = 8;
- ExploreWebView view = 14;
+ optional ExploreWebView view = 14;
- string overview_sort_by = 15;
- bool overview_sort_asc = 16;
- string overview_expanded_dimension = 17;
+ optional string overview_sort_by = 15;
+ optional bool overview_sort_asc = 16;
+ optional string overview_expanded_dimension = 17;
- string time_dimension_measure = 18;
- string time_dimension_chart_type = 19;
- bool time_dimension_pin = 20;
+ optional string time_dimension_measure = 18;
+ optional string time_dimension_chart_type = 19;
+ optional bool time_dimension_pin = 20;
repeated string pivot_rows = 21;
repeated string pivot_cols = 22;
- string pivot_sort_by = 23;
- bool pivot_sort_asc = 24;
+ optional string pivot_sort_by = 23;
+ optional bool pivot_sort_asc = 24;
}
enum ExploreComparisonMode {
diff --git a/runtime/compilers/rillv1/parse_explore.go b/runtime/compilers/rillv1/parse_explore.go
index 63ad936b0f72..43d3e5a21188 100644
--- a/runtime/compilers/rillv1/parse_explore.go
+++ b/runtime/compilers/rillv1/parse_explore.go
@@ -12,7 +12,7 @@ import (
)
type ExploreYAML struct {
- commonYAML `yaml:",inline"` // Not accessed here, only setting it so we can use KnownFields for YAML parsing
+ commonYAML `yaml:",inline"` // Not accessed here, only setting it so we can use KnownFields for YAML parsing
Title string `yaml:"title"`
Description string `yaml:"description"`
MetricsView string `yaml:"metrics_view"`
@@ -214,14 +214,22 @@ func (p *Parser) parseExplore(node *Node) error {
presetMeasuresSelector = tmp.Defaults.Measures.Proto()
}
+ var tr *string
+ if tmp.Defaults.TimeRange != "" {
+ tr = &tmp.Defaults.TimeRange
+ }
+ var compareDim *string
+ if tmp.Defaults.ComparisonDimension != "" {
+ compareDim = &tmp.Defaults.ComparisonDimension
+ }
defaultPreset = &runtimev1.ExplorePreset{
Dimensions: presetDimensions,
DimensionsSelector: presetDimensionsSelector,
Measures: presetMeasures,
MeasuresSelector: presetMeasuresSelector,
- TimeRange: tmp.Defaults.TimeRange,
+ TimeRange: tr,
ComparisonMode: mode,
- ComparisonDimension: tmp.Defaults.ComparisonDimension,
+ ComparisonDimension: compareDim,
}
}
diff --git a/runtime/compilers/rillv1/parse_metrics_view.go b/runtime/compilers/rillv1/parse_metrics_view.go
index dcdf90ea09b4..678b596bef5c 100644
--- a/runtime/compilers/rillv1/parse_metrics_view.go
+++ b/runtime/compilers/rillv1/parse_metrics_view.go
@@ -4,30 +4,29 @@ import (
"fmt"
"strings"
"time"
+ // Load IANA time zone data
+ _ "time/tzdata"
runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1"
"github.com/rilldata/rill/runtime/pkg/duration"
"gopkg.in/yaml.v3"
-
- // Load IANA time zone data
- _ "time/tzdata"
)
// MetricsViewYAML is the raw structure of a MetricsView resource defined in YAML
type MetricsViewYAML struct {
commonYAML `yaml:",inline"` // Not accessed here, only setting it so we can use KnownFields for YAML parsing
- Title string `yaml:"title"`
- DisplayName string `yaml:"display_name"` // Backwards compatibility
- Description string `yaml:"description"`
- Model string `yaml:"model"`
- Database string `yaml:"database"`
- DatabaseSchema string `yaml:"database_schema"`
- Table string `yaml:"table"`
- TimeDimension string `yaml:"timeseries"`
- Watermark string `yaml:"watermark"`
- SmallestTimeGrain string `yaml:"smallest_time_grain"`
- FirstDayOfWeek uint32 `yaml:"first_day_of_week"`
- FirstMonthOfYear uint32 `yaml:"first_month_of_year"`
+ Title string `yaml:"title"`
+ DisplayName string `yaml:"display_name"` // Backwards compatibility
+ Description string `yaml:"description"`
+ Model string `yaml:"model"`
+ Database string `yaml:"database"`
+ DatabaseSchema string `yaml:"database_schema"`
+ Table string `yaml:"table"`
+ TimeDimension string `yaml:"timeseries"`
+ Watermark string `yaml:"watermark"`
+ SmallestTimeGrain string `yaml:"smallest_time_grain"`
+ FirstDayOfWeek uint32 `yaml:"first_day_of_week"`
+ FirstMonthOfYear uint32 `yaml:"first_month_of_year"`
Dimensions []*struct {
Name string
Label string
@@ -872,14 +871,22 @@ func (p *Parser) parseMetricsView(node *Node) error {
if len(spec.DefaultMeasures) == 0 {
presetMeasuresSelector = &runtimev1.FieldSelector{Selector: &runtimev1.FieldSelector_All{All: true}}
}
+ var tr *string
+ if spec.DefaultTimeRange != "" {
+ tr = &spec.DefaultTimeRange
+ }
+ var compareDim *string
+ if spec.DefaultComparisonDimension != "" {
+ compareDim = &spec.DefaultComparisonDimension
+ }
e.ExploreSpec.DefaultPreset = &runtimev1.ExplorePreset{
Dimensions: spec.DefaultDimensions,
DimensionsSelector: presetDimensionsSelector,
Measures: spec.DefaultMeasures,
MeasuresSelector: presetMeasuresSelector,
- TimeRange: spec.DefaultTimeRange,
+ TimeRange: tr,
ComparisonMode: exploreComparisonMode,
- ComparisonDimension: spec.DefaultComparisonDimension,
+ ComparisonDimension: compareDim,
}
return nil
diff --git a/web-admin/src/features/embeds/ExploreEmbed.svelte b/web-admin/src/features/embeds/ExploreEmbed.svelte
index a3a1a6d0578c..3c9f4b6168b7 100644
--- a/web-admin/src/features/embeds/ExploreEmbed.svelte
+++ b/web-admin/src/features/embeds/ExploreEmbed.svelte
@@ -1,9 +1,8 @@
-
+{#if schemaError}
+
+{:else if timeRangeSummaryError}
+
+{:else if $dashboardStore}
+
+{/if}
diff --git a/web-common/src/features/dashboards/url-state/convertPresetToMetricsExplore.ts b/web-common/src/features/dashboards/url-state/convertPresetToMetricsExplore.ts
new file mode 100644
index 000000000000..87a0794d78bb
--- /dev/null
+++ b/web-common/src/features/dashboards/url-state/convertPresetToMetricsExplore.ts
@@ -0,0 +1,413 @@
+import { splitWhereFilter } from "@rilldata/web-common/features/dashboards/filters/measure-filters/measure-filter-utils";
+import {
+ type PivotChipData,
+ PivotChipType,
+} from "@rilldata/web-common/features/dashboards/pivot/types";
+import { SortDirection } from "@rilldata/web-common/features/dashboards/proto-state/derived-types";
+import type { MetricsExplorerEntity } from "@rilldata/web-common/features/dashboards/stores/metrics-explorer-entity";
+import { TDDChart } from "@rilldata/web-common/features/dashboards/time-dimension-details/types";
+import {
+ getMultiFieldError,
+ getSingleFieldError,
+} from "@rilldata/web-common/features/dashboards/url-state/error-message-helpers";
+import {
+ FromURLParamTDDChartMap,
+ FromURLParamTimeDimensionMap,
+ ToActivePageViewMap,
+} from "@rilldata/web-common/features/dashboards/url-state/mappers";
+import {
+ getMapFromArray,
+ getMissingValues,
+} from "@rilldata/web-common/lib/arrayUtils";
+import { TIME_GRAIN } from "@rilldata/web-common/lib/time/config";
+import type { DashboardTimeControls } from "@rilldata/web-common/lib/time/types";
+import { DashboardState_ActivePage } from "@rilldata/web-common/proto/gen/rill/ui/v1/dashboard_pb";
+import {
+ type MetricsViewSpecDimensionV2,
+ type MetricsViewSpecMeasureV2,
+ V1ExploreComparisonMode,
+ type V1ExplorePreset,
+ type V1ExploreSpec,
+ V1ExploreWebView,
+ type V1MetricsViewSpec,
+} from "@rilldata/web-common/runtime-client";
+
+/**
+ * Converts a V1ExplorePreset to our internal metrics explore state.
+ * V1ExplorePreset could come from url state, bookmark, alert or report.
+ */
+export function convertPresetToMetricsExplore(
+ metricsView: V1MetricsViewSpec,
+ explore: V1ExploreSpec,
+ preset: V1ExplorePreset,
+) {
+ const entity: Partial = {};
+ const errors: Error[] = [];
+
+ const measures = getMapFromArray(
+ metricsView.measures?.filter((m) => explore.measures?.includes(m.name!)) ??
+ [],
+ (m) => m.name!,
+ );
+ const dimensions = getMapFromArray(
+ metricsView.dimensions?.filter((d) =>
+ explore.dimensions?.includes(d.name!),
+ ) ?? [],
+ (d) => d.name!,
+ );
+
+ if (preset.view) {
+ entity.activePage = Number(ToActivePageViewMap[preset.view] ?? "0");
+ }
+
+ if (preset.where) {
+ const { dimensionFilters, dimensionThresholdFilters } = splitWhereFilter(
+ preset.where,
+ );
+ entity.whereFilter = dimensionFilters;
+ entity.dimensionThresholdFilters = dimensionThresholdFilters;
+ }
+
+ const { entity: trEntity, errors: trErrors } = fromTimeRangesParams(
+ preset,
+ dimensions,
+ );
+ Object.assign(entity, trEntity);
+ errors.push(...trErrors);
+
+ const { entity: ovEntity, errors: ovErrors } = fromOverviewUrlParams(
+ measures,
+ dimensions,
+ explore,
+ preset,
+ );
+ Object.assign(entity, ovEntity);
+ errors.push(...ovErrors);
+
+ const { entity: tddEntity, errors: tddErrors } = fromTimeDimensionUrlParams(
+ measures,
+ preset,
+ );
+ Object.assign(entity, tddEntity);
+ errors.push(...tddErrors);
+
+ const { entity: pivotEntity, errors: pivotErrors } = fromPivotUrlParams(
+ measures,
+ dimensions,
+ preset,
+ );
+ Object.assign(entity, pivotEntity);
+ errors.push(...pivotErrors);
+
+ return { entity, errors };
+}
+
+function fromTimeRangesParams(
+ preset: V1ExplorePreset,
+ dimensions: Map,
+) {
+ const entity: Partial = {};
+ const errors: Error[] = [];
+
+ if (preset.timeRange) {
+ const { timeRange, error } = fromTimeRangeUrlParam(preset.timeRange);
+ if (error) errors.push(error);
+ entity.selectedTimeRange = timeRange;
+ }
+
+ if (preset.timezone) {
+ entity.selectedTimezone = preset.timezone;
+ }
+
+ if (preset.compareTimeRange) {
+ const { timeRange, error } = fromTimeRangeUrlParam(preset.compareTimeRange);
+ if (error) errors.push(error);
+ entity.selectedComparisonTimeRange = timeRange;
+ entity.showTimeComparison = true;
+ // unset compare dimension
+ entity.selectedComparisonDimension = "";
+ }
+
+ if (preset.comparisonDimension) {
+ if (dimensions.has(preset.comparisonDimension)) {
+ entity.selectedComparisonDimension = preset.comparisonDimension;
+ // unset compare time ranges
+ entity.selectedComparisonTimeRange = undefined;
+ entity.showTimeComparison = false;
+ } else {
+ errors.push(
+ getSingleFieldError("compare dimension", preset.comparisonDimension),
+ );
+ }
+ }
+
+ if (
+ preset.comparisonMode ===
+ V1ExploreComparisonMode.EXPLORE_COMPARISON_MODE_NONE
+ ) {
+ // unset all comparison setting if mode is none
+ entity.selectedComparisonTimeRange = undefined;
+ entity.selectedComparisonDimension = "";
+ entity.showTimeComparison = false;
+ }
+
+ // TODO: grain
+
+ return { entity, errors };
+}
+
+function fromTimeRangeUrlParam(tr: string): {
+ timeRange?: DashboardTimeControls;
+ error?: Error;
+} {
+ // TODO: validation
+ return {
+ timeRange: {
+ name: tr,
+ } as DashboardTimeControls,
+ };
+
+ // return {
+ // error: new Error(`unknown time range: ${tr}`),
+ // };
+}
+
+function fromOverviewUrlParams(
+ measures: Map,
+ dimensions: Map,
+ explore: V1ExploreSpec,
+ preset: V1ExplorePreset,
+) {
+ const entity: Partial = {};
+ const errors: Error[] = [];
+
+ if (preset.measures?.length) {
+ const selectedMeasures = preset.measures.filter((m) => measures.has(m));
+ const missingMeasures = getMissingValues(selectedMeasures, preset.measures);
+ if (missingMeasures.length) {
+ errors.push(getMultiFieldError("measure", missingMeasures));
+ }
+
+ entity.allMeasuresVisible =
+ selectedMeasures.length === explore.measures?.length;
+ entity.visibleMeasureKeys = new Set(selectedMeasures);
+ }
+
+ if (preset.dimensions?.length) {
+ const selectedDimensions = preset.dimensions.filter((d) =>
+ dimensions.has(d),
+ );
+ const missingDimensions = getMissingValues(
+ selectedDimensions,
+ preset.dimensions,
+ );
+ if (missingDimensions.length) {
+ errors.push(getMultiFieldError("dimension", missingDimensions));
+ }
+
+ entity.allDimensionsVisible =
+ selectedDimensions.length === explore.dimensions?.length;
+ entity.visibleDimensionKeys = new Set(selectedDimensions);
+ }
+
+ if (preset.overviewSortBy) {
+ if (measures.has(preset.overviewSortBy)) {
+ entity.leaderboardMeasureName = preset.overviewSortBy;
+ } else {
+ errors.push(
+ getSingleFieldError("sort by measure", preset.overviewSortBy),
+ );
+ }
+ }
+
+ if (preset.overviewSortAsc !== undefined) {
+ entity.sortDirection = preset.overviewSortAsc
+ ? SortDirection.ASCENDING
+ : SortDirection.DESCENDING;
+ }
+
+ if (preset.overviewExpandedDimension !== undefined) {
+ if (preset.overviewExpandedDimension === "") {
+ entity.selectedDimensionName = "";
+ // if preset didnt have a view then this is a dimension table unset.
+ if (
+ preset.view === V1ExploreWebView.EXPLORE_ACTIVE_PAGE_UNSPECIFIED ||
+ preset.view === undefined
+ ) {
+ entity.activePage = DashboardState_ActivePage.DEFAULT;
+ }
+ } else if (dimensions.has(preset.overviewExpandedDimension)) {
+ entity.selectedDimensionName = preset.overviewExpandedDimension;
+ if (
+ preset.view === V1ExploreWebView.EXPLORE_ACTIVE_PAGE_OVERVIEW ||
+ preset.view === V1ExploreWebView.EXPLORE_ACTIVE_PAGE_UNSPECIFIED ||
+ preset.view === undefined
+ ) {
+ entity.activePage = DashboardState_ActivePage.DIMENSION_TABLE;
+ }
+ } else {
+ errors.push(
+ getSingleFieldError(
+ "expanded dimension",
+ preset.overviewExpandedDimension,
+ ),
+ );
+ }
+ }
+
+ return { entity, errors };
+}
+
+function fromTimeDimensionUrlParams(
+ measures: Map,
+ preset: V1ExplorePreset,
+): {
+ entity: Partial;
+ errors: Error[];
+} {
+ if (preset.timeDimensionMeasure === undefined) {
+ return {
+ entity: {},
+ errors: [],
+ };
+ }
+
+ const errors: Error[] = [];
+
+ let expandedMeasureName = preset.timeDimensionMeasure;
+ if (expandedMeasureName && !measures.has(expandedMeasureName)) {
+ expandedMeasureName = "";
+ errors.push(getSingleFieldError("expanded measure", expandedMeasureName));
+ }
+
+ // unset
+ if (expandedMeasureName === "") {
+ return {
+ entity: {
+ tdd: {
+ expandedMeasureName: "",
+ chartType: TDDChart.DEFAULT,
+ pinIndex: -1,
+ },
+ },
+ errors,
+ };
+ }
+
+ const entity: Partial = {
+ tdd: {
+ expandedMeasureName,
+ chartType: preset.timeDimensionChartType
+ ? FromURLParamTDDChartMap[preset.timeDimensionChartType]
+ : TDDChart.DEFAULT,
+ pinIndex: preset.timeDimensionPin ? Number(preset.timeDimensionPin) : -1,
+ },
+ };
+
+ return {
+ entity,
+ errors,
+ };
+}
+
+function fromPivotUrlParams(
+ measures: Map,
+ dimensions: Map,
+ preset: V1ExplorePreset,
+): {
+ entity: Partial;
+ errors: Error[];
+} {
+ const errors: Error[] = [];
+
+ const mapPivotEntry = (entry: string): PivotChipData | undefined => {
+ if (entry in FromURLParamTimeDimensionMap) {
+ const grain = FromURLParamTimeDimensionMap[entry];
+ return {
+ id: grain,
+ title: TIME_GRAIN[grain]?.label,
+ type: PivotChipType.Time,
+ };
+ }
+
+ if (measures.has(entry)) {
+ const m = measures.get(entry)!;
+ return {
+ id: entry,
+ title: m.label || m.name || "Unknown",
+ type: PivotChipType.Measure,
+ };
+ }
+
+ if (dimensions.has(entry)) {
+ const d = dimensions.get(entry)!;
+ return {
+ id: entry,
+ title: d.label || d.name || "Unknown",
+ type: PivotChipType.Dimension,
+ };
+ }
+
+ errors.push(getSingleFieldError("pivot entry", entry));
+
+ return undefined;
+ };
+
+ let hasSomePivotFields = false;
+
+ const rowDimensions: PivotChipData[] = [];
+ if (preset.pivotRows) {
+ preset.pivotRows.forEach((pivotRow) => {
+ const chip = mapPivotEntry(pivotRow);
+ if (!chip) return;
+ rowDimensions.push(chip);
+ });
+ hasSomePivotFields = true;
+ }
+
+ const colMeasures: PivotChipData[] = [];
+ const colDimensions: PivotChipData[] = [];
+ if (preset.pivotCols) {
+ preset.pivotCols.forEach((pivotRow) => {
+ const chip = mapPivotEntry(pivotRow);
+ if (!chip) return;
+ if (chip.type === PivotChipType.Measure) {
+ colMeasures.push(chip);
+ } else {
+ colDimensions.push(chip);
+ }
+ });
+ hasSomePivotFields = true;
+ }
+
+ if (!hasSomePivotFields) {
+ return {
+ entity: {},
+ errors,
+ };
+ }
+
+ return {
+ entity: {
+ pivot: {
+ active: preset.view === V1ExploreWebView.EXPLORE_ACTIVE_PAGE_PIVOT,
+ rows: {
+ dimension: rowDimensions,
+ },
+ columns: {
+ measure: colMeasures,
+ dimension: colDimensions,
+ },
+ // TODO: other fields
+ expanded: {},
+ sorting: [],
+ columnPage: 1,
+ rowPage: 1,
+ enableComparison: false,
+ activeCell: null,
+ rowJoinType: "nest",
+ },
+ },
+ errors,
+ };
+}
diff --git a/web-common/src/features/dashboards/url-state/convertURLToExplorePreset.ts b/web-common/src/features/dashboards/url-state/convertURLToExplorePreset.ts
new file mode 100644
index 000000000000..51e044f416de
--- /dev/null
+++ b/web-common/src/features/dashboards/url-state/convertURLToExplorePreset.ts
@@ -0,0 +1,300 @@
+import { createAndExpression } from "@rilldata/web-common/features/dashboards/stores/filter-utils";
+import {
+ getMultiFieldError,
+ getSingleFieldError,
+} from "@rilldata/web-common/features/dashboards/url-state/error-message-helpers";
+import { convertFilterParamToExpression } from "@rilldata/web-common/features/dashboards/url-state/filters/converters";
+import {
+ FromURLParamTimeDimensionMap,
+ FromURLParamViewMap,
+} from "@rilldata/web-common/features/dashboards/url-state/mappers";
+import {
+ getMapFromArray,
+ getMissingValues,
+} from "@rilldata/web-common/lib/arrayUtils";
+import {
+ type MetricsViewSpecDimensionV2,
+ type MetricsViewSpecMeasureV2,
+ V1ExploreComparisonMode,
+ type V1ExplorePreset,
+ type V1ExploreSpec,
+ V1ExploreWebView,
+ type V1Expression,
+ type V1MetricsViewSpec,
+ V1Operation,
+} from "@rilldata/web-common/runtime-client";
+
+export function convertURLToExplorePreset(
+ searchParams: URLSearchParams,
+ metricsView: V1MetricsViewSpec,
+ explore: V1ExploreSpec,
+) {
+ const preset: V1ExplorePreset = {};
+ const errors: Error[] = [];
+
+ const measures = getMapFromArray(
+ metricsView.measures?.filter((m) => explore.measures?.includes(m.name!)) ??
+ [],
+ (m) => m.name!,
+ );
+ const dimensions = getMapFromArray(
+ metricsView.dimensions?.filter((d) =>
+ explore.dimensions?.includes(d.name!),
+ ) ?? [],
+ (d) => d.name!,
+ );
+
+ if (searchParams.has("vw")) {
+ preset.view = FromURLParamViewMap[searchParams.get("vw") as string];
+ }
+
+ if (searchParams.has("f")) {
+ const { expr, errors: filterErrors } = fromFilterUrlParam(
+ searchParams.get("f") as string,
+ );
+ if (filterErrors) errors.push(...filterErrors);
+ if (expr) preset.where = expr;
+ }
+
+ const { preset: trPreset, errors: trErrors } = fromTimeRangesParams(
+ searchParams,
+ dimensions,
+ );
+ Object.assign(preset, trPreset);
+ errors.push(...trErrors);
+
+ const { preset: ovPreset, errors: ovErrors } = fromOverviewUrlParams(
+ searchParams,
+ measures,
+ dimensions,
+ explore,
+ );
+ Object.assign(preset, ovPreset);
+ errors.push(...ovErrors);
+
+ const { preset: tddPreset, errors: tddErrors } = fromTimeDimensionUrlParams(
+ searchParams,
+ measures,
+ );
+ Object.assign(preset, tddPreset);
+ errors.push(...tddErrors);
+
+ const { preset: pivotPreset, errors: pivotErrors } = fromPivotUrlParams(
+ searchParams,
+ measures,
+ dimensions,
+ );
+ Object.assign(preset, pivotPreset);
+ errors.push(...pivotErrors);
+
+ return { preset, errors };
+}
+
+function fromFilterUrlParam(filter: string): {
+ expr?: V1Expression;
+ errors?: Error[];
+} {
+ try {
+ let expr = convertFilterParamToExpression(filter);
+ // if root is not AND/OR then add AND
+ if (
+ expr?.cond?.op !== V1Operation.OPERATION_AND &&
+ expr?.cond?.op !== V1Operation.OPERATION_OR
+ ) {
+ expr = createAndExpression([expr]);
+ }
+ return { expr };
+ } catch (e) {
+ return { errors: [e] };
+ }
+}
+
+function fromTimeRangesParams(
+ searchParams: URLSearchParams,
+ dimensions: Map,
+) {
+ const preset: V1ExplorePreset = {};
+ const errors: Error[] = [];
+
+ if (searchParams.has("tr")) {
+ preset.timeRange = searchParams.get("tr") as string;
+ // TODO: parse and return errors
+ }
+ if (searchParams.has("tz")) {
+ preset.timezone = searchParams.get("tz") as string;
+ }
+
+ if (searchParams.has("ctr")) {
+ preset.compareTimeRange = searchParams.get("ctr") as string;
+ preset.comparisonMode =
+ V1ExploreComparisonMode.EXPLORE_COMPARISON_MODE_TIME;
+ // TODO: parse and return errors
+ }
+ if (searchParams.has("cd")) {
+ const comparisonDimension = searchParams.get("cd") as string;
+ // unsetting a default from url
+ if (comparisonDimension === "") {
+ preset.comparisonDimension = "";
+ preset.comparisonMode =
+ V1ExploreComparisonMode.EXPLORE_COMPARISON_MODE_NONE;
+ } else if (dimensions.has(comparisonDimension)) {
+ preset.comparisonDimension = comparisonDimension;
+ preset.comparisonMode ??=
+ V1ExploreComparisonMode.EXPLORE_COMPARISON_MODE_DIMENSION;
+ } else {
+ errors.push(
+ getSingleFieldError("compare dimension", comparisonDimension),
+ );
+ }
+ }
+
+ // TODO: grain from time range ?
+
+ return { preset, errors };
+}
+
+function fromOverviewUrlParams(
+ searchParams: URLSearchParams,
+ measures: Map,
+ dimensions: Map,
+ explore: V1ExploreSpec,
+) {
+ const preset: V1ExplorePreset = {};
+ const errors: Error[] = [];
+
+ if (searchParams.has("o.m")) {
+ const mes = searchParams.get("o.m") as string;
+ if (mes === "*") {
+ preset.measures = explore.measures ?? [];
+ } else {
+ const selectedMeasures = mes.split(",").filter((m) => measures.has(m));
+ preset.measures = selectedMeasures;
+ const missingMeasures = getMissingValues(
+ mes.split(","),
+ selectedMeasures,
+ );
+ if (missingMeasures.length) {
+ errors.push(getMultiFieldError("measure", missingMeasures));
+ }
+ }
+ }
+
+ if (searchParams.has("o.d")) {
+ const dims = searchParams.get("o.d") as string;
+ if (dims === "*") {
+ preset.dimensions = explore.dimensions ?? [];
+ } else {
+ const selectedDimensions = dims
+ .split(",")
+ .filter((d) => dimensions.has(d));
+ preset.dimensions = selectedDimensions;
+ const missingDimensions = getMissingValues(
+ dims.split(","),
+ selectedDimensions,
+ );
+ if (missingDimensions.length) {
+ errors.push(getMultiFieldError("dimension", missingDimensions));
+ }
+ }
+ }
+
+ if (searchParams.has("o.sb")) {
+ const sortBy = searchParams.get("o.sb") as string;
+ if (measures.has(sortBy)) {
+ preset.overviewSortBy = sortBy;
+ } else {
+ errors.push(getSingleFieldError("sort by measure", sortBy));
+ }
+ }
+
+ if (searchParams.has("o.sd")) {
+ preset.overviewSortAsc = (searchParams.get("o.sd") as string) === "ASC";
+ }
+
+ if (searchParams.has("o.ed")) {
+ const dim = searchParams.get("o.ed") as string;
+ if (
+ dimensions.has(dim) ||
+ // we are unsetting from a default preset
+ dim === ""
+ ) {
+ preset.overviewExpandedDimension = dim;
+ } else {
+ errors.push(getSingleFieldError("expanded dimension", dim));
+ }
+ }
+
+ return { preset, errors };
+}
+
+function fromTimeDimensionUrlParams(
+ searchParams: URLSearchParams,
+ measures: Map,
+) {
+ const preset: V1ExplorePreset = {};
+ const errors: Error[] = [];
+
+ if (searchParams.has("tdd.m")) {
+ const mes = searchParams.get("tdd.m") as string;
+ if (
+ measures.has(mes) ||
+ // we are unsetting from a default preset
+ mes === ""
+ ) {
+ preset.timeDimensionMeasure = mes;
+ } else {
+ errors.push(getSingleFieldError("expanded measure", mes));
+ }
+ }
+ if (searchParams.has("tdd.ct")) {
+ preset.timeDimensionChartType = searchParams.get("tdd.ct") as string;
+ }
+ if (searchParams.has("tdd.p")) {
+ preset.timeDimensionPin = true;
+ }
+
+ return {
+ preset,
+ errors,
+ };
+}
+
+function fromPivotUrlParams(
+ searchParams: URLSearchParams,
+ measures: Map,
+ dimensions: Map,
+) {
+ const preset: V1ExplorePreset = {};
+ const errors: Error[] = [];
+
+ if (searchParams.has("p.r")) {
+ const rows = (searchParams.get("p.r") as string).split(",");
+ const validRows = rows.filter(
+ (r) => dimensions.has(r) || r in FromURLParamTimeDimensionMap,
+ );
+ preset.pivotRows = validRows;
+ const missingRows = getMissingValues(rows, validRows);
+ if (missingRows.length) {
+ errors.push(getMultiFieldError("pivot row", missingRows));
+ }
+ }
+
+ if (searchParams.has("p.c")) {
+ const cols = (searchParams.get("p.c") as string).split(",");
+ const validCols = cols.filter(
+ (r) =>
+ dimensions.has(r) ||
+ measures.has(r) ||
+ r in FromURLParamTimeDimensionMap,
+ );
+ preset.pivotCols = validCols;
+ const missingCols = getMissingValues(cols, validCols);
+ if (missingCols.length) {
+ errors.push(getMultiFieldError("pivot column", missingCols));
+ }
+ }
+
+ // TODO: other fields
+
+ return { preset, errors };
+}
diff --git a/web-common/src/features/dashboards/url-state/defaults.ts b/web-common/src/features/dashboards/url-state/defaults.ts
index bc1930beec52..3d6faca1b1e3 100644
--- a/web-common/src/features/dashboards/url-state/defaults.ts
+++ b/web-common/src/features/dashboards/url-state/defaults.ts
@@ -1,6 +1,19 @@
import { SortDirection } from "@rilldata/web-common/features/dashboards/proto-state/derived-types";
import { TDDChart } from "@rilldata/web-common/features/dashboards/time-dimension-details/types";
+import {
+ V1ExploreComparisonMode,
+ V1ExploreWebView,
+} from "@rilldata/web-common/runtime-client";
+export const URLStateDefaultView =
+ V1ExploreWebView.EXPLORE_ACTIVE_PAGE_OVERVIEW;
+
+export const URLStateDefaultTimeRange = "inf";
export const URLStateDefaultTimezone = "UTC";
+
+export const URLStateDefaultCompareMode =
+ V1ExploreComparisonMode.EXPLORE_COMPARISON_MODE_NONE;
+
export const URLStateDefaultSortDirection = SortDirection.DESCENDING;
+
export const URLStateDefaultTDDChartType = TDDChart.DEFAULT;
diff --git a/web-common/src/features/dashboards/url-state/error-message-helpers.ts b/web-common/src/features/dashboards/url-state/error-message-helpers.ts
new file mode 100644
index 000000000000..42cd50308f49
--- /dev/null
+++ b/web-common/src/features/dashboards/url-state/error-message-helpers.ts
@@ -0,0 +1,10 @@
+export function getSingleFieldError(fieldLabel: string, field: string) {
+ return new Error(`Select ${fieldLabel}: "${field}" is not valid.`);
+}
+
+export function getMultiFieldError(fieldLabel: string, fields: string[]) {
+ const plural = fields.length > 1;
+ return new Error(
+ `Select ${fieldLabel}${plural ? "s" : ""}: "${fields.join(",")}" ${plural ? "are" : "is"} not valid.`,
+ );
+}
diff --git a/web-common/src/features/dashboards/url-state/url-state-test-data.ts b/web-common/src/features/dashboards/url-state/url-state-test-data.ts
index 39ccccf2a6e4..f74803eeba12 100644
--- a/web-common/src/features/dashboards/url-state/url-state-test-data.ts
+++ b/web-common/src/features/dashboards/url-state/url-state-test-data.ts
@@ -1,3 +1,4 @@
+import { createAndExpression } from "@rilldata/web-common/features/dashboards/stores/filter-utils";
import type { MetricsExplorerEntity } from "@rilldata/web-common/features/dashboards/stores/metrics-explorer-entity";
import { TDDChart } from "@rilldata/web-common/features/dashboards/time-dimension-details/types";
@@ -8,9 +9,14 @@ export const URLStateTestMetricsExplorerEntity: Partial =
visibleDimensionKeys: new Set(["publisher", "domain"]),
allDimensionsVisible: true,
+ whereFilter: createAndExpression([]),
+ dimensionThresholdFilters: [],
+
selectedDimensionName: "",
selectedTimezone: "UTC",
sortDirection: 2,
+ selectedComparisonDimension: "",
+ selectedComparisonTimeRange: undefined,
leaderboardMeasureName: "impressions",
diff --git a/web-common/src/features/dashboards/url-state/url-state.spec.ts b/web-common/src/features/dashboards/url-state/url-state.spec.ts
index c33ee34de1b7..7a273ca4c595 100644
--- a/web-common/src/features/dashboards/url-state/url-state.spec.ts
+++ b/web-common/src/features/dashboards/url-state/url-state.spec.ts
@@ -16,6 +16,8 @@ import {
AD_BIDS_PUBLISHER_DIMENSION,
} from "@rilldata/web-common/features/dashboards/stores/test-data/data";
import { TDDChart } from "@rilldata/web-common/features/dashboards/time-dimension-details/types";
+import { convertPresetToMetricsExplore } from "@rilldata/web-common/features/dashboards/url-state/convertPresetToMetricsExplore";
+import { convertURLToExplorePreset } from "@rilldata/web-common/features/dashboards/url-state/convertURLToExplorePreset";
import { getMetricsExplorerFromUrl } from "@rilldata/web-common/features/dashboards/url-state/fromUrl";
import { getUrlFromMetricsExplorer } from "@rilldata/web-common/features/dashboards/url-state/toUrl";
import { URLStateTestMetricsExplorerEntity } from "@rilldata/web-common/features/dashboards/url-state/url-state-test-data";
@@ -454,6 +456,20 @@ function testEntity(
expect(url.toString()).to.eq(expectedUrl);
+ const { preset: presetFromUrl } = convertURLToExplorePreset(
+ url.searchParams,
+ AD_BIDS_METRICS_3_MEASURES_DIMENSIONS,
+ explore,
+ );
+ const { entity: entityFromPreset } = convertPresetToMetricsExplore(
+ AD_BIDS_METRICS_3_MEASURES_DIMENSIONS,
+ explore,
+ {
+ ...(preset ?? {}),
+ ...presetFromUrl,
+ },
+ );
+
const { entity: actualEntity } = getMetricsExplorerFromUrl(
url.searchParams,
AD_BIDS_METRICS_3_MEASURES_DIMENSIONS,
@@ -464,4 +480,9 @@ function testEntity(
...URLStateTestMetricsExplorerEntity,
...entity,
});
+
+ expect(actualEntity).toEqual({
+ ...URLStateTestMetricsExplorerEntity,
+ ...entityFromPreset,
+ });
}
diff --git a/web-common/src/lib/arrayUtils.ts b/web-common/src/lib/arrayUtils.ts
index 089a12e6b279..0a6caf14ec43 100644
--- a/web-common/src/lib/arrayUtils.ts
+++ b/web-common/src/lib/arrayUtils.ts
@@ -40,3 +40,10 @@ export function arrayOrderedEquals(src: T[], tar: T[]) {
}
return true;
}
+
+/**
+ * Returns values in tar that are missing in src.
+ */
+export function getMissingValues(src: T[], tar: T[]) {
+ return tar.filter((v) => !src.includes(v));
+}
diff --git a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts
index dc8d9440d774..0e21138c3c50 100644
--- a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts
+++ b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts
@@ -2386,24 +2386,29 @@ export class ExplorePreset extends Message {
*/
measuresSelector?: FieldSelector;
+ /**
+ * @generated from field: optional rill.runtime.v1.Expression where = 25;
+ */
+ where?: Expression;
+
/**
* Time range for the explore.
* It corresponds to the `range` property of the explore's `time_ranges`.
* If not found in `time_ranges`, it should be added to the list.
*
- * @generated from field: string time_range = 6;
+ * @generated from field: optional string time_range = 6;
*/
- timeRange = "";
+ timeRange?: string;
/**
- * @generated from field: string timezone = 11;
+ * @generated from field: optional string timezone = 11;
*/
- timezone = "";
+ timezone?: string;
/**
- * @generated from field: string time_grain = 12;
+ * @generated from field: optional string time_grain = 12;
*/
- timeGrain = "";
+ timeGrain?: string;
/**
* Comparison mode.
@@ -2420,44 +2425,44 @@ export class ExplorePreset extends Message {
/**
* If comparison_mode is EXPLORE_COMPARISON_MODE_DIMENSION, this indicates the dimension to use.
*
- * @generated from field: string comparison_dimension = 8;
+ * @generated from field: optional string comparison_dimension = 8;
*/
- comparisonDimension = "";
+ comparisonDimension?: string;
/**
- * @generated from field: rill.runtime.v1.ExploreWebView view = 14;
+ * @generated from field: optional rill.runtime.v1.ExploreWebView view = 14;
*/
- view = ExploreWebView.EXPLORE_ACTIVE_PAGE_UNSPECIFIED;
+ view?: ExploreWebView;
/**
- * @generated from field: string overview_sort_by = 15;
+ * @generated from field: optional string overview_sort_by = 15;
*/
- overviewSortBy = "";
+ overviewSortBy?: string;
/**
- * @generated from field: bool overview_sort_asc = 16;
+ * @generated from field: optional bool overview_sort_asc = 16;
*/
- overviewSortAsc = false;
+ overviewSortAsc?: boolean;
/**
- * @generated from field: string overview_expanded_dimension = 17;
+ * @generated from field: optional string overview_expanded_dimension = 17;
*/
- overviewExpandedDimension = "";
+ overviewExpandedDimension?: string;
/**
- * @generated from field: string time_dimension_measure = 18;
+ * @generated from field: optional string time_dimension_measure = 18;
*/
- timeDimensionMeasure = "";
+ timeDimensionMeasure?: string;
/**
- * @generated from field: string time_dimension_chart_type = 19;
+ * @generated from field: optional string time_dimension_chart_type = 19;
*/
- timeDimensionChartType = "";
+ timeDimensionChartType?: string;
/**
- * @generated from field: bool time_dimension_pin = 20;
+ * @generated from field: optional bool time_dimension_pin = 20;
*/
- timeDimensionPin = false;
+ timeDimensionPin?: boolean;
/**
* @generated from field: repeated string pivot_rows = 21;
@@ -2470,14 +2475,14 @@ export class ExplorePreset extends Message {
pivotCols: string[] = [];
/**
- * @generated from field: string pivot_sort_by = 23;
+ * @generated from field: optional string pivot_sort_by = 23;
*/
- pivotSortBy = "";
+ pivotSortBy?: string;
/**
- * @generated from field: bool pivot_sort_asc = 24;
+ * @generated from field: optional bool pivot_sort_asc = 24;
*/
- pivotSortAsc = false;
+ pivotSortAsc?: boolean;
constructor(data?: PartialMessage) {
super();
@@ -2491,23 +2496,24 @@ export class ExplorePreset extends Message {
{ no: 9, name: "dimensions_selector", kind: "message", T: FieldSelector },
{ no: 4, name: "measures", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
{ no: 10, name: "measures_selector", kind: "message", T: FieldSelector },
- { no: 6, name: "time_range", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 11, name: "timezone", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 12, name: "time_grain", kind: "scalar", T: 9 /* ScalarType.STRING */ },
+ { no: 25, name: "where", kind: "message", T: Expression, opt: true },
+ { no: 6, name: "time_range", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 11, name: "timezone", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 12, name: "time_grain", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
{ no: 7, name: "comparison_mode", kind: "enum", T: proto3.getEnumType(ExploreComparisonMode) },
{ no: 13, name: "compare_time_range", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
- { no: 8, name: "comparison_dimension", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 14, name: "view", kind: "enum", T: proto3.getEnumType(ExploreWebView) },
- { no: 15, name: "overview_sort_by", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 16, name: "overview_sort_asc", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
- { no: 17, name: "overview_expanded_dimension", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 18, name: "time_dimension_measure", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 19, name: "time_dimension_chart_type", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 20, name: "time_dimension_pin", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
+ { no: 8, name: "comparison_dimension", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 14, name: "view", kind: "enum", T: proto3.getEnumType(ExploreWebView), opt: true },
+ { no: 15, name: "overview_sort_by", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 16, name: "overview_sort_asc", kind: "scalar", T: 8 /* ScalarType.BOOL */, opt: true },
+ { no: 17, name: "overview_expanded_dimension", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 18, name: "time_dimension_measure", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 19, name: "time_dimension_chart_type", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 20, name: "time_dimension_pin", kind: "scalar", T: 8 /* ScalarType.BOOL */, opt: true },
{ no: 21, name: "pivot_rows", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
{ no: 22, name: "pivot_cols", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
- { no: 23, name: "pivot_sort_by", kind: "scalar", T: 9 /* ScalarType.STRING */ },
- { no: 24, name: "pivot_sort_asc", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
+ { no: 23, name: "pivot_sort_by", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
+ { no: 24, name: "pivot_sort_asc", kind: "scalar", T: 8 /* ScalarType.BOOL */, opt: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial): ExplorePreset {
diff --git a/web-common/src/runtime-client/gen/index.schemas.ts b/web-common/src/runtime-client/gen/index.schemas.ts
index 2742dae2bbb1..363bb717e30b 100644
--- a/web-common/src/runtime-client/gen/index.schemas.ts
+++ b/web-common/src/runtime-client/gen/index.schemas.ts
@@ -1854,6 +1854,7 @@ export interface V1ExplorePreset {
/** Measures to show. If `measures_selector` is set, this will only be set in `state.valid_spec`. */
measures?: string[];
measuresSelector?: V1FieldSelector;
+ where?: V1Expression;
/** Time range for the explore.
It corresponds to the `range` property of the explore's `time_ranges`.
If not found in `time_ranges`, it should be added to the list. */
diff --git a/web-local/src/routes/(viz)/explore/[name]/+page.svelte b/web-local/src/routes/(viz)/explore/[name]/+page.svelte
index 3cc4ed5b9e58..ab4d4b98de19 100644
--- a/web-local/src/routes/(viz)/explore/[name]/+page.svelte
+++ b/web-local/src/routes/(viz)/explore/[name]/+page.svelte
@@ -6,7 +6,6 @@
import { selectedMockUserStore } from "@rilldata/web-common/features/dashboards/granular-access-policies/stores";
import DashboardURLStateSync from "@rilldata/web-common/features/dashboards/url-state/DashboardURLStateSync.svelte";
import StateManagersProvider from "@rilldata/web-common/features/dashboards/state-managers/StateManagersProvider.svelte";
- import DashboardStateProvider from "@rilldata/web-common/features/dashboards/stores/DashboardStateProvider.svelte";
import { useProjectParser } from "@rilldata/web-common/features/entity-management/resource-selectors";
import { useExploreValidSpec } from "@rilldata/web-common/features/explores/selectors";
import { runtime } from "@rilldata/web-common/runtime-client/runtime-store";
@@ -41,8 +40,6 @@
);
$: mockUserHasNoAccess =
$selectedMockUserStore && $exploreQuery.error?.response?.status === 404;
-
- console.log("???");
@@ -70,13 +67,11 @@
{:else}
{#key exploreName}
-
-
-
-
-
-
-
+
+
+
+
+
{/key}
{/if}
diff --git a/web-local/src/routes/(viz)/explore/[name]/+page.ts b/web-local/src/routes/(viz)/explore/[name]/+page.ts
index f2eeaa78b06c..a5dc530b5d3f 100644
--- a/web-local/src/routes/(viz)/explore/[name]/+page.ts
+++ b/web-local/src/routes/(viz)/explore/[name]/+page.ts
@@ -1,5 +1,6 @@
import type { MetricsExplorerEntity } from "@rilldata/web-common/features/dashboards/stores/metrics-explorer-entity";
-import { getMetricsExplorerFromUrl } from "@rilldata/web-common/features/dashboards/url-state/fromUrl";
+import { convertPresetToMetricsExplore } from "@rilldata/web-common/features/dashboards/url-state/convertPresetToMetricsExplore";
+import { convertURLToExplorePreset } from "@rilldata/web-common/features/dashboards/url-state/convertURLToExplorePreset";
import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient.js";
import {
getRuntimeServiceGetExploreQueryKey,
@@ -45,25 +46,36 @@ export const load = async ({ params, depends, url }) => {
}
let partialMetrics: Partial = {};
+ const errors: Error[] = [];
if (
metricsViewResource.metricsView.state?.validSpec &&
exploreResource.explore.state?.validSpec &&
url
) {
- const { entity, errors } = getMetricsExplorerFromUrl(
+ const { preset, errors: errorsFromPreset } = convertURLToExplorePreset(
url.searchParams,
metricsViewResource.metricsView.state.validSpec,
exploreResource.explore.state.validSpec,
- exploreResource.explore.state.validSpec.defaultPreset ?? {},
);
+ errors.push(...errorsFromPreset);
+ const { entity, errors: errorsFromEntity } =
+ convertPresetToMetricsExplore(
+ metricsViewResource.metricsView.state.validSpec,
+ exploreResource.explore.state.validSpec,
+ {
+ ...(exploreResource.explore.state.validSpec.defaultPreset ?? {}),
+ ...preset,
+ },
+ );
+ errors.push(...errorsFromEntity);
partialMetrics = entity;
- if (errors.length) console.log(errors); // TODO
}
return {
explore: exploreResource,
metricsView: metricsViewResource,
partialMetrics,
+ errors,
};
} catch (e) {
console.error(e);