mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
feat: Allow users to define custom column aliases for charts (#996)
<img width="1337" height="988" alt="image" src="https://github.com/user-attachments/assets/80d83541-3fa9-4ebb-b54c-3caccbd86e90" /> Resolves HDX-1719
This commit is contained in:
parent
2741646c80
commit
33fc071dfa
5 changed files with 55 additions and 4 deletions
7
.changeset/chilled-goats-marry.md
Normal file
7
.changeset/chilled-goats-marry.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
"@hyperdx/common-utils": patch
|
||||
"@hyperdx/api": patch
|
||||
"@hyperdx/app": patch
|
||||
---
|
||||
|
||||
feat: Allow users to define custom column aliases for charts
|
||||
|
|
@ -483,6 +483,9 @@ export function formatResponseForTimeChart({
|
|||
};
|
||||
} = {};
|
||||
|
||||
const isSingleValueColumn = valueColumns.length === 1;
|
||||
const hasGroupColumns = groupColumns.length > 0;
|
||||
|
||||
for (const row of data) {
|
||||
const date = new Date(row[timestampColumn.name]);
|
||||
const ts = date.getTime() / 1000;
|
||||
|
|
@ -491,7 +494,8 @@ export function formatResponseForTimeChart({
|
|||
const tsBucket = tsBucketMap.get(ts) ?? {};
|
||||
|
||||
const keyName = [
|
||||
valueColumn.name,
|
||||
// Simplify the display name if there's only one series and a group by
|
||||
...(isSingleValueColumn && hasGroupColumns ? [] : [valueColumn.name]),
|
||||
...groupColumns.map(g => row[g.name]),
|
||||
].join(' · ');
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ import HDXMarkdownChart from '../HDXMarkdownChart';
|
|||
|
||||
import { AggFnSelectControlled } from './AggFnSelect';
|
||||
import DBNumberChart from './DBNumberChart';
|
||||
import { InputControlled } from './InputControlled';
|
||||
import { InputControlled, TextInputControlled } from './InputControlled';
|
||||
import { MetricNameSelect } from './MetricNameSelect';
|
||||
import { NumberFormatInput } from './NumberFormat';
|
||||
import { SourceSelectControlled } from './SourceSelect';
|
||||
|
|
@ -163,6 +163,17 @@ function ChartSeriesEditorComponent({
|
|||
<Divider
|
||||
label={
|
||||
<Group gap="xs">
|
||||
<Text size="xxs">Alias</Text>
|
||||
|
||||
<div style={{ width: 150 }}>
|
||||
<TextInputControlled
|
||||
name={`${namePrefix}alias`}
|
||||
control={control}
|
||||
placeholder="Series alias"
|
||||
onChange={() => onSubmit()}
|
||||
size="xs"
|
||||
/>
|
||||
</div>
|
||||
{(index ?? -1) > 0 && (
|
||||
<Button
|
||||
variant="subtle"
|
||||
|
|
@ -179,6 +190,7 @@ function ChartSeriesEditorComponent({
|
|||
c="dark.2"
|
||||
labelPosition="right"
|
||||
mb={8}
|
||||
mt="sm"
|
||||
/>
|
||||
<Flex gap="sm" mt="xs" align="center">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import {
|
|||
InputProps,
|
||||
PasswordInput,
|
||||
PasswordInputProps,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
} from '@mantine/core';
|
||||
|
||||
interface InputControlledProps<T extends FieldValues>
|
||||
|
|
@ -23,6 +25,32 @@ interface PasswordInputControlledProps<T extends FieldValues>
|
|||
rules?: Parameters<Control<T>['register']>[1];
|
||||
}
|
||||
|
||||
interface TextInputControlledProps<T extends FieldValues>
|
||||
extends Omit<TextInputProps, 'name' | 'style'>,
|
||||
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'name' | 'size'> {
|
||||
name: Path<T>;
|
||||
control: Control<T>;
|
||||
rules?: Parameters<Control<T>['register']>[1];
|
||||
}
|
||||
|
||||
export function TextInputControlled<T extends FieldValues>({
|
||||
name,
|
||||
control,
|
||||
rules,
|
||||
...props
|
||||
}: TextInputControlledProps<T>) {
|
||||
return (
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
rules={rules}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<TextInput {...props} {...field} error={error?.message} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function InputControlled<T extends FieldValues>({
|
||||
name,
|
||||
control,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const setChartSelectsAlias = (config: ChartConfigWithOptDateRange) => {
|
|||
...config,
|
||||
select: config.select.map(s => ({
|
||||
...s,
|
||||
alias: s.alias ?? `${s.aggFn}(${s.metricName})`, // use an alias if one isn't already set
|
||||
alias: s.alias || `${s.aggFn}(${s.metricName})`, // use an alias if one isn't already set
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
|
@ -396,7 +396,7 @@ async function renderSelectList(
|
|||
}
|
||||
|
||||
return chSql`${expr}${
|
||||
select.alias != null
|
||||
select.alias != null && select.alias.trim() !== ''
|
||||
? chSql` AS "${{ UNSAFE_RAW_SQL: select.alias }}"`
|
||||
: []
|
||||
}`;
|
||||
|
|
|
|||
Loading…
Reference in a new issue