|
@@ -8,7 +8,12 @@ import {CustomMeasurementCollection} from 'sentry/utils/customMeasurements/custo
|
|
|
import {TableData} from 'sentry/utils/discover/discoverQuery';
|
|
|
import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
|
|
|
import {getMetricsApiRequestQuery, getSeriesName, groupByOp} from 'sentry/utils/metrics';
|
|
|
-import {formatMRI, getMRI, getUseCaseFromMRI} from 'sentry/utils/metrics/mri';
|
|
|
+import {
|
|
|
+ formatMRI,
|
|
|
+ formatMRIField,
|
|
|
+ getMRI,
|
|
|
+ getUseCaseFromMRI,
|
|
|
+} from 'sentry/utils/metrics/mri';
|
|
|
import {OnDemandControlContext} from 'sentry/utils/performance/contexts/onDemandControl';
|
|
|
import {MetricSearchBar} from 'sentry/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/metricSearchBar';
|
|
|
import {FieldValueOption} from 'sentry/views/discover/table/queryField';
|
|
@@ -62,8 +67,21 @@ export const MetricsConfig: DatasetConfig<MetricsApiResponse, MetricsApiResponse
|
|
|
filterAggregateParams: filterMetricMRIs,
|
|
|
filterYAxisAggregateParams: () => option => filterMetricMRIs(option),
|
|
|
getGroupByFieldOptions: getTagsForMetric,
|
|
|
+ getFieldHeaderMap: getFormattedMRIHeaders,
|
|
|
};
|
|
|
|
|
|
+function getFormattedMRIHeaders(query?: WidgetQuery) {
|
|
|
+ if (!query) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+
|
|
|
+ return (query.fields || []).reduce((acc, field, index) => {
|
|
|
+ const fieldAlias = query.fieldAliases?.[index];
|
|
|
+ acc[field] = fieldAlias || formatMRIField(field);
|
|
|
+ return acc;
|
|
|
+ }, {});
|
|
|
+}
|
|
|
+
|
|
|
function getMetricTimeseriesSortOptions(_, widgetQuery) {
|
|
|
if (!widgetQuery.columns) {
|
|
|
return [];
|
|
@@ -220,15 +238,10 @@ function handleMetricTableOrderByReset(widgetQuery: WidgetQuery, newFields: stri
|
|
|
return handleOrderByReset(widgetQuery, newFields);
|
|
|
}
|
|
|
|
|
|
-export function transformMetricsResponseToTable(
|
|
|
- data: MetricsApiResponse,
|
|
|
- {aggregates}: WidgetQuery
|
|
|
-): TableData {
|
|
|
- // TODO(ddm): get rid of this mapping, it is only needed because the API returns
|
|
|
- // `op(metric_name)` instead of `op(mri)`
|
|
|
- const rows = mapResponse(data, aggregates).groups.map((group, index) => {
|
|
|
- const groupColumn = mapDerivedMetricsToFields(group.by);
|
|
|
- const value = mapDerivedMetricsToFields(group.totals);
|
|
|
+export function transformMetricsResponseToTable(data: MetricsApiResponse): TableData {
|
|
|
+ const rows = data.groups.map((group, index) => {
|
|
|
+ const groupColumn = mapMetricGroupsToFields(group.by);
|
|
|
+ const value = mapMetricGroupsToFields(group.totals);
|
|
|
return {
|
|
|
id: String(index),
|
|
|
...groupColumn,
|
|
@@ -243,9 +256,8 @@ export function transformMetricsResponseToTable(
|
|
|
return {meta, data: rows};
|
|
|
}
|
|
|
|
|
|
-function mapDerivedMetricsToFields(
|
|
|
- results: Record<string, number | string | null> | undefined,
|
|
|
- mapToKey?: string
|
|
|
+function mapMetricGroupsToFields(
|
|
|
+ results: Record<string, number | string | null> | undefined
|
|
|
) {
|
|
|
if (!results) {
|
|
|
return {};
|
|
@@ -253,7 +265,7 @@ function mapDerivedMetricsToFields(
|
|
|
|
|
|
const mappedResults: typeof results = {};
|
|
|
for (const [key, value] of Object.entries(results)) {
|
|
|
- mappedResults[mapToKey ?? key] = value;
|
|
|
+ mappedResults[key] = value;
|
|
|
}
|
|
|
return mappedResults;
|
|
|
}
|
|
@@ -261,8 +273,8 @@ function mapDerivedMetricsToFields(
|
|
|
function changeObjectValuesToTypes(
|
|
|
obj: Record<string, number | string | null> | undefined
|
|
|
) {
|
|
|
- return Object.keys(obj ?? {}).reduce((acc, key) => {
|
|
|
- acc[key] = key.includes('@') ? 'number' : 'string';
|
|
|
+ return Object.entries(obj ?? {}).reduce((acc, [key, value]) => {
|
|
|
+ acc[key] = typeof value;
|
|
|
return acc;
|
|
|
}, {});
|
|
|
}
|
|
@@ -352,30 +364,3 @@ function getMetricRequest(
|
|
|
query: requestData,
|
|
|
});
|
|
|
}
|
|
|
-
|
|
|
-const mapResponse = (data: MetricsApiResponse, field: string[]): MetricsApiResponse => {
|
|
|
- const mappedGroups = data.groups.map(group => {
|
|
|
- return {
|
|
|
- ...group,
|
|
|
- by: group.by,
|
|
|
- series: swapKeys(group.series, field),
|
|
|
- totals: swapKeys(group.totals, field),
|
|
|
- };
|
|
|
- });
|
|
|
-
|
|
|
- return {...data, groups: mappedGroups};
|
|
|
-};
|
|
|
-
|
|
|
-const swapKeys = (obj: Record<string, unknown> | undefined, newKeys: string[]) => {
|
|
|
- if (!obj) {
|
|
|
- return {};
|
|
|
- }
|
|
|
-
|
|
|
- const keys = Object.keys(obj);
|
|
|
- const values = Object.values(obj);
|
|
|
- const newObj = {};
|
|
|
- keys.forEach((_, index) => {
|
|
|
- newObj[newKeys[index]] = values[index];
|
|
|
- });
|
|
|
- return newObj;
|
|
|
-};
|