Skip to content

Commit

Permalink
feat(dashboard-renderer): merge context into queries [MA-2304] (#1178)
Browse files Browse the repository at this point in the history
- Data providers are in charge of merging context -- it's different for
  metric cards vs charts.
- Pick a reasonable default for timezone if not provided.
- Translate time spec to timeframe for metric cards, unfortunately.
- Externalize `analytics-utilities` dependency
  • Loading branch information
adorack authored Feb 23, 2024
1 parent 65431a4 commit 75799c0
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<QueryDataProvider
v-slot="{ data }"
:context="context"
:query="query"
:query-ready="queryReady"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<template #tile="{ tile, style }">
<DashboardTile
class="tile-container"
:context="mergedContext"
:definition="tile.meta"
:height="parseInt(style.height)"
/>
Expand Down Expand Up @@ -61,6 +62,17 @@ const gridTiles = computed(() => {
})
})
const mergedContext = computed(() => {
if (props.context.tz) {
return props.context
}
return {
...props.context,
tz: (new Intl.DateTimeFormat()).resolvedOptions().timeZone,
}
})
// Right now, tiles don't have unique keys. Perhaps in the future they will,
// and we can use that instead of `index` as the fragment key.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
</div>
</template>
<script setup lang="ts">
import type { TileDefinition } from '../types'
import { ChartTypes } from '../types'
import { ChartTypes, type DashboardRendererContext, type TileDefinition } from '../types'
import type {
Component,
} from 'vue'
Expand All @@ -24,6 +23,7 @@ import GoldenSignalsRenderer from './GoldenSignalsRenderer.vue'
const props = withDefaults(defineProps<{
definition: TileDefinition,
context: DashboardRendererContext,
height?: number
}>(), {
height: DEFAULT_TILE_HEIGHT,
Expand All @@ -45,6 +45,7 @@ const componentData = computed(() => {
component,
rendererProps: {
query: props.definition.query,
context: props.context,
queryReady: true, // TODO: Pipelining
chartOptions: props.definition.chart,
height: props.height,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,48 @@
<script setup lang="ts">
import type { MetricCardOptions, RendererProps } from '../types'
import { MetricsProviderInternal, MetricsConsumer } from '@kong-ui-public/analytics-metric-provider'
import { computed } from 'vue'
import { computed, type Ref } from 'vue'
import { GranularityKeys, Timeframe, TimePeriods } from '@kong-ui-public/analytics-utilities'
// Unlike AnalyticsChart, the metric card package doesn't currently expose its options
// in a convenient interface.
type ProviderProps = InstanceType<typeof MetricsProviderInternal>['$props']
const props = defineProps<RendererProps<MetricCardOptions>>()
const overrideTimeframe: Ref<Timeframe> = computed(() => {
// Convert the timeframe to a v4 timespec.
// Ideally, metric cards would natively support timespecs, but for right now,
// we're sticking with this interface.
const timeSpec = props.context.timeSpec
if (timeSpec.type === 'absolute') {
return new Timeframe({
key: 'custom',
timeframeText: 'custom',
display: 'custom',
startCustom: timeSpec.start,
endCustom: timeSpec.end,
timeframeLength: () => 0,
defaultResponseGranularity: GranularityKeys.DAILY,
dataGranularity: GranularityKeys.DAILY,
isRelative: false,
allowedTiers: ['free', 'plus', 'enterprise'],
})
}
const relativePeriod = TimePeriods.get(timeSpec.time_range)
if (!relativePeriod) {
// Should never happen; if it does, at least make it clear what the problem is.
throw new Error('Unknown time range')
}
return relativePeriod
})
const options = computed<ProviderProps>(() => ({
overrideTimeframe: overrideTimeframe.value,
tz: props.context.tz,
additionalFilters: props.context.filters,
longCardTitles: props.chartOptions.longCardTitles,
description: props.chartOptions.description,
hasTrendAccess: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ import { computed, inject, onUnmounted, ref } from 'vue'
import useSWRV from 'swrv'
import { useSwrvState } from '@kong-ui-public/core'
import composables from '../composables'
import type { AnalyticsBridge, ExploreQuery } from '@kong-ui-public/analytics-utilities'
import type { AnalyticsBridge, ExploreFilter, ExploreQuery } from '@kong-ui-public/analytics-utilities'
import { INJECT_QUERY_PROVIDER } from '../constants'
import type { DashboardRendererContext } from '../types'
const props = defineProps<{
context: DashboardRendererContext
query: ExploreQuery
queryReady: boolean,
queryReady: boolean
}>()
const emit = defineEmits(['queryComplete'])
Expand All @@ -51,7 +53,7 @@ const queryBridge: AnalyticsBridge | undefined = inject(INJECT_QUERY_PROVIDER)
const queryKey = () => {
// SWRV can't accept `false` as a key, so use a more complicated conditional to match its `IKey` interface.
if (props.queryReady && queryBridge) {
return JSON.stringify(props.query)
return JSON.stringify([props.query, props.context])
}
return null
Expand All @@ -66,8 +68,25 @@ onUnmounted(() => {
const { data: v4Data, error, isValidating } = useSWRV(queryKey, async () => {
try {
const mergedFilters: ExploreFilter[] = []
if (props.query.filters) {
mergedFilters.push(...props.query.filters)
}
mergedFilters.push(...props.context.filters)
const mergedQuery: ExploreQuery = {
...props.query,
time_range: {
...props.context.timeSpec,
tz: props.context.tz,
},
filters: mergedFilters,
}
// Note that queryBridge is guaranteed to be set here because SWRV won't execute the query if the key is null.
return queryBridge?.queryFn(props.query, abortController)
return queryBridge?.queryFn(mergedQuery, abortController)
} catch (e: any) {
// Note: 'Range not allowed' is defined by the API, therefore cannot be stored as string translation
errorMessage.value = e?.response?.data?.message === 'Range not allowed for this tier'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<QueryDataProvider
v-slot="{ data }"
:context="context"
:query="query"
:query-ready="queryReady"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<QueryDataProvider
v-slot="{ data }"
:context="context"
:query="query"
:query-ready="queryReady"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ExploreFilter, ExploreQuery, TimeRangeV4 } from '@kong-ui-public/a
export interface DashboardRendererContext {
filters: ExploreFilter[]
timeSpec: TimeRangeV4
tz?: string
}

export enum ChartTypes {
Expand Down Expand Up @@ -408,6 +409,7 @@ export type DashboardConfig = FromSchema<typeof dashboardConfigSchema>

export interface RendererProps<T> {
query: ExploreQuery
context: DashboardRendererContext
queryReady: boolean
chartOptions: T
height: number
Expand Down
8 changes: 7 additions & 1 deletion packages/analytics/dashboard-renderer/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ const config = mergeConfig(sharedViteConfig, defineConfig({
},
rollupOptions: {
// Make sure to externalize deps that shouldn't be bundled into your library
external: ['@kong-ui-public/analytics-chart', '@kong-ui-public/analytics-metric-provider', 'swrv'],
external: [
'@kong-ui-public/analytics-chart',
'@kong-ui-public/analytics-metric-provider',
'@kong-ui-public/analytics-utilities',
'swrv',
],
output: {
// Provide global variables to use in the UMD build for externalized deps
globals: {
'@kong-ui-public/analytics-chart': 'kong-ui-public-analytics-chart',
'@kong-ui-public/analytics-metric-provider': 'kong-ui-public-analytics-metric-provider',
'@kong-ui-public/analytics-utilities': 'kong-ui-public-analytics-utilities',
swrv: 'swrv',
},
},
Expand Down

0 comments on commit 75799c0

Please sign in to comment.