Skip to content

Commit

Permalink
Feat/AN-4112 implement order by selection (#69)
Browse files Browse the repository at this point in the history
* implements license fetching and interval selection

* add tests for intervalUtils

* fix ceiling of timestamp for DAY interval

* add tests

* fix linting

* delete unnecessary export of enum

* implement metric selection

* implement dimension selection

* fix linting errors

* add metric support

* add metric to query and check for null instead of undefined

* implements groupBy selection

* fix linting

* implements reordering of GroupBys and fixes position of Add Button

* make props readonly

* implements order By selection

* splits orderBy state into two seperate states to fix rendering and renames variables

* lint
  • Loading branch information
MGJamJam authored May 8, 2024
1 parent 813b386 commit 00dd1a5
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 13 deletions.
6 changes: 3 additions & 3 deletions bitmovin-analytics-datasource/src/components/GroupByRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ export function GroupByRow(props: Props) {
};

const addGroupByInput = () => {
setSelectedGroupBys((prevState) => [...prevState, { name: '', label: '' }]);
setSelectedGroupBys((prevState) => [...prevState, {}]);
};

return (
<VerticalGroup>
{selectedGroupBys?.map((item, index, groupBys) => (
{selectedGroupBys.map((item, index, groupBys) => (
<GroupByInput
key={index}
groupBy={item}
Expand All @@ -81,7 +81,7 @@ export function GroupByRow(props: Props) {
/>
))}
<Box paddingTop={selectedGroupBys.length === 0 ? 0.5 : 0}>
<IconButton name="plus-square" tooltip="Add Group By" onClick={() => addGroupByInput()} size="xxl" />
<IconButton name="plus-square" tooltip="Add Group By" onClick={() => addGroupByInput()} size="xl" />
</Box>
</VerticalGroup>
);
Expand Down
63 changes: 63 additions & 0 deletions bitmovin-analytics-datasource/src/components/OrderByInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import { SelectableValue } from '@grafana/data';
import { HorizontalGroup, IconButton, RadioButtonGroup, Select } from '@grafana/ui';

import { QueryAttribute } from '../types/queryAttributes';
import { QueryAdAttribute } from '../types/queryAdAttributes';
import { QuerySortOrder } from '../types/queryOrderBy';
import { REORDER_DIRECTION } from './GroupByInput';

type Props = {
readonly isAdAnalytics: boolean;
readonly attribute: SelectableValue<QueryAttribute | QueryAdAttribute>;
readonly selectableOrderByAttributes: Array<SelectableValue<QueryAttribute | QueryAdAttribute>>;
readonly onAttributeChange: (newValue: SelectableValue<QueryAdAttribute | QueryAttribute>) => void;
readonly sortOrder: QuerySortOrder;
readonly onSortOrderChange: (newValue: QuerySortOrder) => void;
readonly onDelete: () => void;
readonly isFirst: boolean;
readonly isLast: boolean;
readonly onReorderOrderBy: (direction: REORDER_DIRECTION) => void;
};

const sortOrderOption: Array<SelectableValue<QuerySortOrder>> = [
{ value: 'ASC', description: 'Sort by ascending', icon: 'sort-amount-up' },
{ value: 'DESC', description: 'Sort by descending', icon: 'sort-amount-down' },
];

export function OrderByInput(props: Props) {
return (
<HorizontalGroup spacing="xs">
<Select
value={props.attribute}
onChange={(value) => props.onAttributeChange(value)}
options={props.selectableOrderByAttributes}
width={30}
/>
<RadioButtonGroup
options={sortOrderOption}
value={props.sortOrder}
onChange={(value) => props.onSortOrderChange(value)}
/>
<IconButton
tooltip="Move down"
onClick={() => props.onReorderOrderBy(REORDER_DIRECTION.DOWN)}
name="arrow-down"
disabled={props.isLast}
/>
<IconButton
tooltip="Move up"
onClick={() => props.onReorderOrderBy(REORDER_DIRECTION.UP)}
name="arrow-up"
disabled={props.isFirst}
/>
<IconButton
tooltip="Delete Group By"
name="trash-alt"
onClick={() => props.onDelete()}
size="lg"
variant="destructive"
/>
</HorizontalGroup>
);
}
121 changes: 121 additions & 0 deletions bitmovin-analytics-datasource/src/components/OrderByRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState } from 'react';
import { Box, IconButton, VerticalGroup } from '@grafana/ui';
import { SelectableValue } from '@grafana/data';
import { difference } from 'lodash';

import { QueryAdAttribute, SELECTABLE_QUERY_AD_ATTRIBUTES } from '../types/queryAdAttributes';
import { QueryAttribute, SELECTABLE_QUERY_ATTRIBUTES } from '../types/queryAttributes';
import { QueryOrderBy, QuerySortOrder } from '../types/queryOrderBy';
import { OrderByInput } from './OrderByInput';
import { REORDER_DIRECTION } from './GroupByInput';

type Props = {
readonly isAdAnalytics: boolean;
readonly onChange: (newOrderBy: QueryOrderBy[]) => void;
};

export function OrderByRow(props: Props) {
const [selectedAttributes, setSelectedAttributes] = useState<
Array<SelectableValue<QueryAdAttribute | QueryAttribute>>
>([]);
const [selectedSortOrders, setSelectedSortOrders] = useState<QuerySortOrder[]>([]);

const mapOrderBysToSelectableValue = (): Array<SelectableValue<QueryAttribute | QueryAdAttribute>> => {
if (props.isAdAnalytics) {
return difference(SELECTABLE_QUERY_AD_ATTRIBUTES, selectedAttributes);
} else {
return difference(SELECTABLE_QUERY_ATTRIBUTES, selectedAttributes);
}
};

const mapSelectedValuesToQueryOrderBy = (
selectedAttributes: Array<SelectableValue<QueryAttribute | QueryAdAttribute>>,
selectedSortOrders: QuerySortOrder[]
): QueryOrderBy[] => {
const queryOrderBys: QueryOrderBy[] = [];
for (let i = 0; i < selectedAttributes.length; i++) {
queryOrderBys.push({
name: selectedAttributes[i].value!,
order: selectedSortOrders[i],
});
}
return queryOrderBys;
};

const deleteOrderByInput = (index: number) => {
const newSelectedAttributes = [...selectedAttributes];
newSelectedAttributes.splice(index, 1);

const newSelectedSortOrders = [...selectedSortOrders];
newSelectedSortOrders.splice(index, 1);

setSelectedAttributes(newSelectedAttributes);
setSelectedSortOrders(newSelectedSortOrders);
props.onChange(mapSelectedValuesToQueryOrderBy(newSelectedAttributes, newSelectedSortOrders));
};

const onAttributesChange = (index: number, newAttribute: SelectableValue<QueryAttribute | QueryAdAttribute>) => {
const newSelectedAttributes = [...selectedAttributes];
newSelectedAttributes.splice(index, 1, newAttribute);
setSelectedAttributes(newSelectedAttributes);

props.onChange(mapSelectedValuesToQueryOrderBy(newSelectedAttributes, selectedSortOrders));
};

const onSortOrdersChange = (index: number, newSortOrder: QuerySortOrder) => {
const newSelectedSortOrders = [...selectedSortOrders];
newSelectedSortOrders.splice(index, 1, newSortOrder);
setSelectedSortOrders(newSelectedSortOrders);

props.onChange(mapSelectedValuesToQueryOrderBy(selectedAttributes, newSelectedSortOrders));
};

const reorderOrderBy = (direction: REORDER_DIRECTION, index: number) => {
const newIndex = direction === REORDER_DIRECTION.UP ? index - 1 : index + 1;

const newSelectedAttributes = [...selectedAttributes];
const attributeToMove = newSelectedAttributes[index];
newSelectedAttributes.splice(index, 1);
newSelectedAttributes.splice(newIndex, 0, attributeToMove);

const newSelectedSortOrders = [...selectedSortOrders];
const sortOrderToMove = newSelectedSortOrders[index];
newSelectedSortOrders.splice(index, 1);
newSelectedSortOrders.splice(newIndex, 0, sortOrderToMove);

setSelectedAttributes(newSelectedAttributes);
setSelectedSortOrders(newSelectedSortOrders);

props.onChange(mapSelectedValuesToQueryOrderBy(newSelectedAttributes, newSelectedSortOrders));
};
const addOrderByInput = () => {
setSelectedAttributes((prevState) => [...prevState, {}]);
setSelectedSortOrders((prevState) => [...prevState, 'ASC']);
};

return (
<VerticalGroup>
{selectedAttributes.map((attribute, index, array) => (
<OrderByInput
key={index}
isAdAnalytics={props.isAdAnalytics}
selectableOrderByAttributes={mapOrderBysToSelectableValue()}
attribute={attribute}
onAttributeChange={(newValue: SelectableValue<QueryAdAttribute | QueryAttribute>) =>
onAttributesChange(index, newValue)
}
sortOrder={selectedSortOrders[index]}
onSortOrderChange={(newValue: QuerySortOrder) => onSortOrdersChange(index, newValue)}
onDelete={() => deleteOrderByInput(index)}
isFirst={index === 0}
isLast={index === array.length - 1}
onReorderOrderBy={(direction: REORDER_DIRECTION) => reorderOrderBy(direction, index)}
/>
))}

<Box paddingTop={selectedAttributes.length === 0 ? 0.5 : 0}>
<IconButton name="plus-square" tooltip="Add Group By" onClick={() => addOrderByInput()} size="xl" />
</Box>
</VerticalGroup>
);
}
10 changes: 10 additions & 0 deletions bitmovin-analytics-datasource/src/components/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { QueryAdAttribute, SELECTABLE_QUERY_AD_ATTRIBUTES } from '../types/query
import { QueryAttribute, SELECTABLE_QUERY_ATTRIBUTES } from '../types/queryAttributes';
import { isMetric, SELECTABLE_METRICS } from '../types/metric';
import { GroupByRow } from './GroupByRow';
import { OrderByRow } from './OrderByRow';
import { QueryOrderBy } from '../types/queryOrderBy';

enum LoadingState {
Default = 'DEFAULT',
Expand Down Expand Up @@ -67,6 +69,11 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
onRunQuery();
};

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

const onFormatAsTimeSeriesChange = (event: ChangeEvent<HTMLInputElement>) => {
setIsTimeSeries(event.currentTarget.checked);
if (event.currentTarget.checked) {
Expand Down Expand Up @@ -140,6 +147,9 @@ export function QueryEditor({ query, onChange, onRunQuery, datasource }: Props)
<InlineField label="Group By" labelWidth={20}>
<GroupByRow isAdAnalytics={datasource.adAnalytics ? true : false} onChange={onGroupByChange} />
</InlineField>
<InlineField label="Order By" labelWidth={20}>
<OrderByRow isAdAnalytics={datasource.adAnalytics ? true : false} onChange={onOrderByChange} />
</InlineField>
<InlineField label="Format as time series" labelWidth={20}>
<InlineSwitch value={isTimeSeries} onChange={onFormatAsTimeSeriesChange}></InlineSwitch>
</InlineField>
Expand Down
13 changes: 3 additions & 10 deletions bitmovin-analytics-datasource/src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import { QueryAttribute } from './types/queryAttributes';
import { QueryAdAttribute } from './types/queryAdAttributes';
import { Metric } from './types/metric';
import { Aggregation } from './types/aggregations';

import { QueryOrderBy } from './types/queryOrderBy';

type AnalyticsQuery = {
filters: Array<{ name: string; operator: string; value: number }>;
groupBy: QueryAttribute[] | QueryAdAttribute[];
orderBy: Array<{ name: string; order: string }>;
orderBy: QueryOrderBy[];
dimension?: QueryAttribute | QueryAdAttribute;
metric?: Metric;
start: Date;
Expand Down Expand Up @@ -73,14 +73,7 @@ export class DataSource extends DataSourceApi<BitmovinAnalyticsDataQuery, MyData
},
],
groupBy: target.groupBy,
orderBy: interval
? [
{
name: interval,
order: 'DESC',
},
]
: [],
orderBy: target.orderBy,
dimension: target.dimension,
metric: target.metric,
start: from,
Expand Down
2 changes: 2 additions & 0 deletions bitmovin-analytics-datasource/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Aggregation } from './types/aggregations';
import { QueryAttribute } from './types/queryAttributes';
import { QueryAdAttribute } from './types/queryAdAttributes';
import { Metric } from './types/metric';
import { QueryOrderBy } from './types/queryOrderBy';

export interface BitmovinAnalyticsDataQuery extends DataQuery {
licenseKey: string;
Expand All @@ -13,6 +14,7 @@ export interface BitmovinAnalyticsDataQuery extends DataQuery {
metric?: Metric;
dimension?: QueryAttribute | QueryAdAttribute;
groupBy: QueryAttribute[] | QueryAdAttribute[];
orderBy: QueryOrderBy[];
}

export const DEFAULT_QUERY: Partial<BitmovinAnalyticsDataQuery> = {};
Expand Down
9 changes: 9 additions & 0 deletions bitmovin-analytics-datasource/src/types/queryOrderBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { QueryAttribute } from './queryAttributes';
import { QueryAdAttribute } from './queryAdAttributes';

export type QuerySortOrder = 'ASC' | 'DESC';

export type QueryOrderBy = {
name: QueryAttribute | QueryAdAttribute;
order: QuerySortOrder;
};

0 comments on commit 00dd1a5

Please sign in to comment.