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);