Skip to content

Commit

Permalink
Feat/AN-4107 implement dimension selection (#66)
Browse files Browse the repository at this point in the history
* implement dimension selection

* fix linting errors

* add metric support

* add metric to query and check for null instead of undefined
  • Loading branch information
MGJamJam authored May 6, 2024
1 parent b82e5c2 commit a231632
Show file tree
Hide file tree
Showing 6 changed files with 656 additions and 14 deletions.
40 changes: 34 additions & 6 deletions bitmovin-analytics-datasource/src/components/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { MyDataSourceOptions, MyQuery } from '../types';
import { fetchLicenses } from '../utils/licenses';
import { DEFAULT_SELECTABLE_QUERY_INTERVAL, SELECTABLE_QUERY_INTERVALS } from '../utils/intervalUtils';
import { DEFAULT_SELECTABLE_AGGREGATION, SELECTABLE_AGGREGATIONS } from '../types/aggregations';
import { SELECTABLE_QUERY_AD_ATTRIBUTES } from '../types/queryAdAttributes';
import { SELECTABLE_QUERY_ATTRIBUTES } from '../types/queryAttributes';
import { isMetric, SELECTABLE_METRICS } from '../types/metric';

enum LoadingState {
Default = 'DEFAULT',
Expand All @@ -22,6 +25,7 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
const [licenseLoadingState, setLicenseLoadingState] = useState<LoadingState>(LoadingState.Default);
const [licenseErrorMessage, setLicenseErrorMessage] = useState('');
const [isTimeSeries, setIsTimeSeries] = useState(true);
const [isDimensionMetricSelected, setIsDimensionMetricSelected] = useState(false);

useEffect(() => {
setLicenseLoadingState(LoadingState.Loading);
Expand All @@ -41,8 +45,19 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
onRunQuery();
};

const onMetricChange = (item: SelectableValue) => {
onChange({ ...query, aggregation: item.value });
const onAggregationChange = (item: SelectableValue) => {
onChange({ ...query, aggregation: item.value, metric: undefined });
onRunQuery();
};

const onDimensionChange = (item: SelectableValue) => {
if (isMetric(item.value)) {
setIsDimensionMetricSelected(true);
onChange({ ...query, aggregation: undefined, dimension: undefined, metric: item.value });
} else {
setIsDimensionMetricSelected(false);
onChange({ ...query, dimension: item.value });
}
onRunQuery();
};

Expand Down Expand Up @@ -95,12 +110,25 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
placeholder={licenseLoadingState === LoadingState.Loading ? 'Loading Licenses' : 'Choose License'}
/>
</InlineField>
<InlineField label="Metric" labelWidth={20}>
{!isDimensionMetricSelected && (
<InlineField label="Metric" labelWidth={20}>
<Select
defaultValue={DEFAULT_SELECTABLE_AGGREGATION}
onChange={(item) => onAggregationChange(item)}
width={40}
options={SELECTABLE_AGGREGATIONS}
/>
</InlineField>
)}
<InlineField label="Dimension" labelWidth={20}>
<Select
defaultValue={DEFAULT_SELECTABLE_AGGREGATION}
onChange={(item) => onMetricChange(item)}
onChange={onDimensionChange}
width={40}
options={SELECTABLE_AGGREGATIONS}
options={
datasource.adAnalytics
? SELECTABLE_QUERY_AD_ATTRIBUTES
: SELECTABLE_QUERY_ATTRIBUTES.concat(SELECTABLE_METRICS)
}
/>
</InlineField>
<InlineField label="Format as time series" labelWidth={20}>
Expand Down
26 changes: 19 additions & 7 deletions bitmovin-analytics-datasource/src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ import { catchError, lastValueFrom, map, Observable, of } from 'rxjs';
import { MixedDataRowList, MyDataSourceOptions, MyQuery, NumberDataRowList } from './types';
import { transformGroupedTimeSeriesData, transformSimpleTimeSeries, transformTableData } from './utils/dataUtils';
import { calculateQueryInterval, QueryInterval } from './utils/intervalUtils';
import { QueryAttribute } from './types/queryAttributes';
import { QueryAdAttribute } from './types/queryAdAttributes';
import { Metric } from './types/metric';
import { Aggregation } from './types/aggregations';

type AnalyticsQuery = {
filters: Array<{ name: string; operator: string; value: number }>;
groupBy: string[];
orderBy: Array<{ name: string; order: string }>;
dimension: string;
dimension?: QueryAttribute | QueryAdAttribute;
metric?: Metric;
start: Date;
end: Date;
licenseKey: string;
Expand Down Expand Up @@ -54,7 +59,6 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
const to = range!.to.toDate();

const promises = options.targets.map(async (target) => {
const urlAppendix = target.aggregation;
const interval = target.interval
? calculateQueryInterval(target.interval!, from.getTime(), to.getTime())
: undefined;
Expand All @@ -76,14 +80,17 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
},
]
: [],
dimension: 'IMPRESSION_ID',
dimension: target.dimension,
metric: target.metric,
start: from,
end: to,
licenseKey: target.licenseKey,
interval: interval,
};

const response = await lastValueFrom(this.request(this.getRequestUrl() + urlAppendix, 'POST', query));
const response = await lastValueFrom(
this.request(this.getRequestUrl(target.metric, target.aggregation), 'POST', query)
);

const dataRows: MixedDataRowList = response.data.data.result.rows;
const columnLabels: Array<{ key: string; label: string }> = response.data.data.result.columnLabels;
Expand Down Expand Up @@ -120,12 +127,17 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
return Promise.all(promises).then((data) => ({ data }));
}

getRequestUrl(): string {
getRequestUrl(metric?: Metric, aggregation?: Aggregation): string {
let url = '/analytics';
if (this.adAnalytics === true) {
return '/analytics/ads/queries/';
url += '/ads';
}

return '/analytics/queries/';
if (metric != null) {
return url + '/metrics/' + metric;
}

return url + '/queries/' + aggregation;
}

request(url: string, method: string, payload?: any): Observable<Record<any, any>> {
Expand Down
7 changes: 6 additions & 1 deletion bitmovin-analytics-datasource/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { DataSourceJsonData } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
import { QueryInterval } from './utils/intervalUtils';
import { Aggregation } from './types/aggregations';
import { QueryAttribute } from './types/queryAttributes';
import { QueryAdAttribute } from './types/queryAdAttributes';
import { Metric } from './types/metric';

export interface MyQuery extends DataQuery {
licenseKey: string;
interval?: QueryInterval | 'AUTO';
aggregation: Aggregation;
aggregation?: Aggregation;
metric?: Metric;
dimension?: QueryAttribute | QueryAdAttribute;
}

export const DEFAULT_QUERY: Partial<MyQuery> = {};
Expand Down
19 changes: 19 additions & 0 deletions bitmovin-analytics-datasource/src/types/metric.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { SelectableValue } from '@grafana/data';

export enum METRICS {
AVG_CONCURRENTVIEWERS = 'avg-concurrentviewers',
MAX_CONCURRENTVIEWERS = 'max-concurrentviewers',
AVG_DROPPED_FRAMES = 'avg-dropped-frames',
}

export type Metric = (typeof METRICS)[keyof typeof METRICS];

export const SELECTABLE_METRICS: Array<SelectableValue<Metric>> = [
{ value: METRICS.AVG_CONCURRENTVIEWERS, label: 'Avg Concurrent Viewers' },
{ value: METRICS.MAX_CONCURRENTVIEWERS, label: 'Max Concurrent Viewers' },
{ value: METRICS.AVG_DROPPED_FRAMES, label: 'Avg Dropped Frames' },
];

export const isMetric = (value: string): boolean => {
return Object.values(METRICS).includes(value as Metric);
};
Loading

0 comments on commit a231632

Please sign in to comment.