Skip to content

Commit

Permalink
Feat/AN-4121 implement aliasby selection (#72)
Browse files Browse the repository at this point in the history
* implement alias By selection

* rename onChange Methods to handle...

* add Default values for query editor (#73)
  • Loading branch information
MGJamJam authored May 14, 2024
1 parent 3b7ab6b commit 9287958
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 55 deletions.
109 changes: 58 additions & 51 deletions bitmovin-analytics-datasource/src/components/QueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { ChangeEvent, useEffect, useState } from 'react';
import { FieldSet, InlineField, InlineSwitch, Input, Select } from '@grafana/ui';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { defaults } from 'lodash';

import { DataSource } from '../datasource';
import { BitmovinDataSourceOptions, BitmovinAnalyticsDataQuery } from '../types';
import { BitmovinDataSourceOptions, BitmovinAnalyticsDataQuery, DEFAULT_QUERY } 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_AGGREGATIONS } from '../types/aggregations';
import { QueryAdAttribute, SELECTABLE_QUERY_AD_ATTRIBUTES } from '../types/queryAdAttributes';
import { QueryAttribute, SELECTABLE_QUERY_ATTRIBUTES } from '../types/queryAttributes';
import { isMetric, SELECTABLE_METRICS } from '../types/metric';
Expand All @@ -25,7 +26,7 @@ enum LoadingState {

type Props = QueryEditorProps<DataSource, BitmovinAnalyticsDataQuery, BitmovinDataSourceOptions>;

export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props) {
export function QueryEditor(props: Props) {
const [selectableLicenses, setSelectableLicenses] = useState<SelectableValue[]>([]);
const [licenseLoadingState, setLicenseLoadingState] = useState<LoadingState>(LoadingState.Default);
const [licenseErrorMessage, setLicenseErrorMessage] = useState('');
Expand All @@ -34,7 +35,7 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)

useEffect(() => {
setLicenseLoadingState(LoadingState.Loading);
fetchLicenses(datasource.apiKey, datasource.baseUrl)
fetchLicenses(props.datasource.apiKey, props.datasource.baseUrl)
.then((licenses) => {
setSelectableLicenses(licenses);
setLicenseLoadingState(LoadingState.Success);
Expand All @@ -43,63 +44,70 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
setLicenseLoadingState(LoadingState.Error);
setLicenseErrorMessage(e.status + ' ' + e.statusText);
});
}, [datasource.apiKey, datasource.baseUrl]);
}, [props.datasource.apiKey, props.datasource.baseUrl]);

const onLicenseChange = (item: SelectableValue) => {
onChange({ ...query, licenseKey: item.value });
onRunQuery();
const query = defaults(props.query, DEFAULT_QUERY);

const handleLicenseChange = (item: SelectableValue) => {
props.onChange({ ...query, licenseKey: item.value });
props.onRunQuery();
};

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

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

const onGroupByChange = (newGroupBys: QueryAdAttribute[] | QueryAttribute[]) => {
onChange({ ...query, groupBy: newGroupBys });
onRunQuery();
const handleGroupByChange = (newGroupBys: QueryAdAttribute[] | QueryAttribute[]) => {
props.onChange({ ...query, groupBy: newGroupBys });
props.onRunQuery();
};

const onOrderByChange = (newOrderBys: QueryOrderBy[]) => {
onChange({ ...query, orderBy: newOrderBys });
onRunQuery();
const handleOrderByChange = (newOrderBys: QueryOrderBy[]) => {
props.onChange({ ...query, orderBy: newOrderBys });
props.onRunQuery();
};

const onFilterChange = (newFilters: QueryFilter[]) => {
onChange({ ...query, filters: newFilters });
onRunQuery();
const handleFilterChange = (newFilters: QueryFilter[]) => {
props.onChange({ ...query, filters: newFilters });
props.onRunQuery();
};

const onLimitChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleLimitBlur = (event: ChangeEvent<HTMLInputElement>) => {
const limit = parseInt(event.target.value, 10);
onChange({ ...query, limit: isNaN(limit) ? undefined : limit });
onRunQuery();
props.onChange({ ...query, limit: isNaN(limit) ? undefined : limit });
props.onRunQuery();
};

const onFormatAsTimeSeriesChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleFormatAsTimeSeriesChange = (event: ChangeEvent<HTMLInputElement>) => {
setIsTimeSeries(event.currentTarget.checked);
if (event.currentTarget.checked) {
onChange({ ...query, interval: 'AUTO' });
props.onChange({ ...query, interval: 'AUTO' });
} else {
onChange({ ...query, interval: undefined });
props.onChange({ ...query, interval: undefined });
}
onRunQuery();
props.onRunQuery();
};

const handleIntervalChange = (item: SelectableValue) => {
props.onChange({ ...query, interval: item.value });
props.onRunQuery();
};

const onIntervalChange = (item: SelectableValue) => {
onChange({ ...query, interval: item.value });
onRunQuery();
const handleAliasByBlur = (event: ChangeEvent<HTMLInputElement>) => {
props.onChange({ ...query, aliasBy: event.target.value });
props.onRunQuery();
};

const renderTimeSeriesOption = () => {
Expand All @@ -108,7 +116,7 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
<InlineField label="Interval" labelWidth={20}>
<Select
defaultValue={DEFAULT_SELECTABLE_QUERY_INTERVAL}
onChange={(item) => onIntervalChange(item)}
onChange={(item) => handleIntervalChange(item)}
width={30}
options={SELECTABLE_QUERY_INTERVALS}
/>
Expand All @@ -126,9 +134,10 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
invalid={licenseLoadingState === LoadingState.Error}
error={`Error when fetching Analytics Licenses: ${licenseErrorMessage}`}
disabled={licenseLoadingState === LoadingState.Error}
required
>
<Select
onChange={onLicenseChange}
onChange={handleLicenseChange}
width={30}
options={selectableLicenses}
noOptionsMessage="No Analytics Licenses found"
Expand All @@ -137,42 +146,40 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
/>
</InlineField>
{!isDimensionMetricSelected && (
<InlineField label="Metric" labelWidth={20}>
<Select
defaultValue={DEFAULT_SELECTABLE_AGGREGATION}
onChange={(item) => onAggregationChange(item)}
width={30}
options={SELECTABLE_AGGREGATIONS}
/>
<InlineField label="Metric" labelWidth={20} required>
<Select onChange={(item) => handleAggregationChange(item)} width={30} options={SELECTABLE_AGGREGATIONS} />
</InlineField>
)}
<InlineField label="Dimension" labelWidth={20}>
<InlineField label="Dimension" labelWidth={20} required>
<Select
onChange={onDimensionChange}
onChange={handleDimensionChange}
width={30}
options={
datasource.adAnalytics
props.datasource.adAnalytics
? SELECTABLE_QUERY_AD_ATTRIBUTES
: SELECTABLE_QUERY_ATTRIBUTES.concat(SELECTABLE_METRICS)
}
/>
</InlineField>
<InlineField label="Filter" labelWidth={20}>
<FilterRow isAdAnalytics={datasource.adAnalytics ? true : false} onChange={onFilterChange} />
<FilterRow isAdAnalytics={props.datasource.adAnalytics ? true : false} onChange={handleFilterChange} />
</InlineField>
<InlineField label="Group By" labelWidth={20}>
<GroupByRow isAdAnalytics={datasource.adAnalytics ? true : false} onChange={onGroupByChange} />
<GroupByRow isAdAnalytics={props.datasource.adAnalytics ? true : false} onChange={handleGroupByChange} />
</InlineField>
<InlineField label="Order By" labelWidth={20}>
<OrderByRow isAdAnalytics={datasource.adAnalytics ? true : false} onChange={onOrderByChange} />
<OrderByRow isAdAnalytics={props.datasource.adAnalytics ? true : false} onChange={handleOrderByChange} />
</InlineField>
<InlineField label="Limit" labelWidth={20}>
<Input type="number" onBlur={onLimitChange} width={30} placeholder="No limit" />
<Input type="number" onBlur={handleLimitBlur} width={30} placeholder="No limit" />
</InlineField>
<InlineField label="Format as time series" labelWidth={20}>
<InlineSwitch value={isTimeSeries} onChange={onFormatAsTimeSeriesChange}></InlineSwitch>
<InlineSwitch value={isTimeSeries} onChange={handleFormatAsTimeSeriesChange}></InlineSwitch>
</InlineField>
{isTimeSeries && renderTimeSeriesOption()}
<InlineField label="Alias By" labelWidth={20}>
<Input placeholder="Naming pattern" onBlur={handleAliasByBlur} />
</InlineField>
</FieldSet>
</div>
);
Expand Down
13 changes: 12 additions & 1 deletion bitmovin-analytics-datasource/src/datasource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
CoreApp,
createDataFrame,
DataQueryRequest,
DataQueryResponse,
Expand All @@ -15,11 +16,13 @@ import {
BitmovinAnalyticsDataQuery,
NumberDataRowList,
BitmovinAnalyticsRequestQuery,
DEFAULT_QUERY,
} from './types';
import { transformGroupedTimeSeriesData, transformSimpleTimeSeries, transformTableData } from './utils/dataUtils';
import { calculateQueryInterval } from './utils/intervalUtils';
import { Metric } from './types/metric';
import { Aggregation } from './types/aggregations';
import { filter } from 'lodash';

export class DataSource extends DataSourceApi<BitmovinAnalyticsDataQuery, BitmovinDataSourceOptions> {
baseUrl: string;
Expand All @@ -36,6 +39,10 @@ export class DataSource extends DataSourceApi<BitmovinAnalyticsDataQuery, Bitmov
this.baseUrl = instanceSettings.url!;
}

getDefaultQuery(_: CoreApp): Partial<BitmovinAnalyticsDataQuery> {
return DEFAULT_QUERY;
}

/**
* The Bitmovin API Response follows these rules:
* - If the interval property is provided in the request query, time series data is returned and the first value of each row is a timestamp in milliseconds.
Expand All @@ -50,7 +57,10 @@ export class DataSource extends DataSourceApi<BitmovinAnalyticsDataQuery, Bitmov
const from = range!.from.toDate();
const to = range!.to.toDate();

const promises = options.targets.map(async (target) => {
//filter disabled queries
const enabledQueries = (options.targets = filter(options.targets, (t) => !t.hide));

const promises = enabledQueries.map(async (target) => {
const interval = target.interval
? calculateQueryInterval(target.interval!, from.getTime(), to.getTime())
: undefined;
Expand Down Expand Up @@ -100,6 +110,7 @@ export class DataSource extends DataSourceApi<BitmovinAnalyticsDataQuery, Bitmov
}

return createDataFrame({
name: target.aliasBy,
fields: fields,
});
});
Expand Down
9 changes: 8 additions & 1 deletion bitmovin-analytics-datasource/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,16 @@ export interface BitmovinAnalyticsDataQuery extends DataQuery {
orderBy: QueryOrderBy[];
limit?: number;
filters: QueryFilter[];
aliasBy?: string;
}

export const DEFAULT_QUERY: Partial<BitmovinAnalyticsDataQuery> = {};
export const DEFAULT_QUERY: Partial<BitmovinAnalyticsDataQuery> = {
licenseKey: '',
interval: 'AUTO',
orderBy: [],
groupBy: [],
filters: [],
};

/**
* These are options configured for each DataSource instance
Expand Down
2 changes: 0 additions & 2 deletions bitmovin-analytics-datasource/src/types/aggregations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ export const SELECTABLE_AGGREGATIONS: Array<{ value: Aggregation; label: string
{ value: 'variance', label: 'Variance' },
{ value: 'median', label: 'Median' },
];

export const DEFAULT_SELECTABLE_AGGREGATION = SELECTABLE_AGGREGATIONS[0];

0 comments on commit 9287958

Please sign in to comment.