Add dimension selection to product analytics visualization designer filter overhaul
Problem to solve
Continues on from Add measure selection token to product analytic... (#462615 - closed)
Adds the next token
to the new filtering UI within the product analytics visualization designer. Allow selecting one or more dimensions defined in our CubeJS schema.
At this stage we will allow selecting any dimension, regardless of which measure has been selected. This allows creating invalid queries but means we don't need to add dependencies between our tokens yet.
Implementation plan
frontend
- Pass the
availableDimensions
down from the query builder tovisualization-filtered-search
. - Update
visualization-filtered-search
:- Compute the applicable dimensions for the selected measure and show these as a token.
- When there are no applicable dimensions, hide the token.
- Filter out previously selected tokens.
- Note: Could be solved separately in Product analytics visualization designer allows... (#414357).
- Update
mapTokenValuesToQuery
andmapQueryToTokenValues
to support dimensions. - Update docs if necessary.
- Update specs.
Here's a rough patch to get started with:
Click to expand
diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_visualization_designer.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_visualization_designer.vue
index d30c64aa621c..4d880a7ffcb8 100644
--- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_visualization_designer.vue
+++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_visualization_designer.vue
@@ -425,12 +425,14 @@ export default {
addFilters,
setSegments,
availableMeasures,
+ availableDimensions,
}"
>
<visualization-filtered-search
v-if="filteringUiEnabled"
:query="queryState.query"
:available-measures="availableMeasures"
+ :available-dimensions="availableDimensions"
data-testid="visualization-filtered-search"
@input="onFilterChange"
@submit="onFilterChange"
diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/filters/visualization_filtered_search.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/filters/visualization_filtered_search.vue
index 3bd47a2b239b..ab2b5afe778f 100644
--- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/filters/visualization_filtered_search.vue
+++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/filters/visualization_filtered_search.vue
@@ -24,6 +24,10 @@ export default {
type: Array,
required: true,
},
+ availableDimensions: {
+ type: Array,
+ required: true,
+ },
},
data() {
return {
@@ -32,22 +36,50 @@ export default {
},
computed: {
availableTokens() {
+ const measureToken = {
+ unique: true,
+ title: s__('ProductAnalytics|Measure'),
+ type: 'measure',
+ operators: [{ value: '=', description: 'is' }],
+ options: this.availableMeasures
+ .filter((measure) => measure.isVisible)
+ .map((measure) => ({
+ title: measure.title,
+ value: measure.name,
+ })),
+ token: GlFilteredSearchToken,
+ };
+
+ if (this.measureDimensions.length < 1) return [measureToken];
+
return [
+ measureToken,
{
- unique: true,
- title: s__('ProductAnalytics|Measure'),
- type: 'measure',
+ unique: false,
+ title: s__('ProductAnalytics|Dimension'),
+ type: 'dimension',
operators: [{ value: '=', description: 'is' }],
- options: this.availableMeasures
- .filter((measure) => measure.isVisible)
- .map((measure) => ({
- title: measure.title,
- value: measure.name,
+ options: this.measureDimensions
+ .filter((dimension) => dimension.isVisible)
+ .map((dimension) => ({
+ title: dimension.title,
+ value: dimension.name,
})),
token: GlFilteredSearchToken,
},
];
},
+ measureDimensions() {
+ if (this.value.length < 1) return [];
+
+ const measureToken = this.value.find((token) => token.type === 'measure');
+
+ if (!measureToken) return [];
+
+ const metric = this.getMetric(measureToken.value.data);
+
+ return this.availableDimensions.filter((d) => this.getMetric(d.name) === metric);
+ },
},
watch: {
query(query) {
@@ -55,6 +87,9 @@ export default {
},
},
methods: {
+ getMetric(measure) {
+ return measure.split('.')[0];
+ },
onSubmit(value) {
this.$emit('submit', {
...DEFAULT_VISUALIZATION_QUERY_STATE().query,
Edited by Jiaan Louw