diff --git a/static/app/views/explore/components/typeBadge.tsx b/static/app/views/explore/components/typeBadge.tsx
index b34b24cf9c06af..0f059abadab6aa 100644
--- a/static/app/views/explore/components/typeBadge.tsx
+++ b/static/app/views/explore/components/typeBadge.tsx
@@ -10,16 +10,16 @@ interface TypeBadgeProps {
}
export function TypeBadge({func, kind}: TypeBadgeProps) {
- if (defined(func)) {
- return {t('aggregation')};
+ if (defined(func) || kind === FieldKind.FUNCTION) {
+ return {t('f(x)')};
}
if (kind === FieldKind.MEASUREMENT) {
- return {t('number')};
+ return {t('number')};
}
if (kind === FieldKind.TAG) {
- return {t('string')};
+ return {t('string')};
}
return null;
diff --git a/static/app/views/explore/tables/columnEditorModal.spec.tsx b/static/app/views/explore/tables/columnEditorModal.spec.tsx
index 18390bb815fda2..5867e77d70d06f 100644
--- a/static/app/views/explore/tables/columnEditorModal.spec.tsx
+++ b/static/app/views/explore/tables/columnEditorModal.spec.tsx
@@ -123,7 +123,7 @@ describe('ColumnEditorModal', function () {
await userEvent.click(screen.getByRole('button', {name: 'Add a Column'}));
- const columns2 = ['id', 'project', 'None'];
+ const columns2 = ['id', 'project', '\u2014'];
screen.getAllByTestId('editor-column').forEach((column, i) => {
expect(column).toHaveTextContent(columns2[i]!);
});
@@ -134,7 +134,7 @@ describe('ColumnEditorModal', function () {
['span.duration', 'number'],
['span.op', 'string'],
];
- await userEvent.click(screen.getByRole('button', {name: 'Column None'}));
+ await userEvent.click(screen.getByRole('button', {name: 'Column \u2014'}));
const columnOptions = await screen.findAllByRole('option');
columnOptions.forEach((option, i) => {
expect(option).toHaveTextContent(options[i]![0]);
diff --git a/static/app/views/explore/tables/columnEditorModal.tsx b/static/app/views/explore/tables/columnEditorModal.tsx
index 5d31bc6c2c3ee6..8126b1f552145d 100644
--- a/static/app/views/explore/tables/columnEditorModal.tsx
+++ b/static/app/views/explore/tables/columnEditorModal.tsx
@@ -242,7 +242,7 @@ function ColumnEditorRow({
);
}
}
- return {!column.column && t('None')};
+ return {column.column || t('\u2014')};
}, [column.column, options]);
return (
@@ -255,7 +255,7 @@ function ColumnEditorRow({
}}
{...attributes}
>
-
- }
- onClick={() => onColumnDelete()}
+ onClick={onColumnDelete}
/>
);
@@ -292,12 +292,18 @@ const RowContainer = styled('div')`
display: flex;
flex-direction: row;
align-items: center;
+ gap: ${space(1)};
:not(:first-child) {
margin-top: ${space(1)};
}
`;
+const StyledButton = styled(Button)`
+ padding-left: 0;
+ padding-right: 0;
+`;
+
const StyledCompactSelect = styled(CompactSelect)`
flex: 1 1;
min-width: 0;
diff --git a/static/app/views/explore/tables/index.tsx b/static/app/views/explore/tables/index.tsx
index c192b3d4b73827..bf61856fbc907d 100644
--- a/static/app/views/explore/tables/index.tsx
+++ b/static/app/views/explore/tables/index.tsx
@@ -9,6 +9,7 @@ import {IconTable} from 'sentry/icons/iconTable';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Confidence} from 'sentry/types/organization';
+import useOrganization from 'sentry/utils/useOrganization';
import {
useExploreFields,
useExploreMode,
@@ -39,6 +40,8 @@ interface ExploreTablesProps extends BaseExploreTablesProps {
}
export function ExploreTables(props: ExploreTablesProps) {
+ const organization = useOrganization();
+
const mode = useExploreMode();
const setMode = useSetExploreMode();
@@ -63,6 +66,8 @@ export function ExploreTables(props: ExploreTablesProps) {
);
}, [fields, setFields, stringTags, numberTags]);
+ const openAggregateColumnEditor = useCallback(() => {}, []);
+
// HACK: This is pretty gross but to not break anything in the
// short term, we avoid introducing/removing any fields on the
// query. So we continue using the existing `mode` value and
@@ -93,6 +98,11 @@ export function ExploreTables(props: ExploreTablesProps) {
} size="sm">
{t('Edit Table')}
+ ) : tab === Mode.AGGREGATE &&
+ organization.features.includes('visibility-explore-aggregate-editor') ? (
+ } size="sm">
+ {t('Edit Table')}
+
) : (
;
- }
-
- render(
-
-
-
-
-
- );
-
- const section = screen.getByTestId('section-visualizes');
-
- // this is the default
- expect(visualizes).toEqual([new Visualize(['count(span.duration)'], {label: 'A'})]);
-
- expect(fields).toEqual([
- 'id',
- 'span.op',
- 'span.description',
- 'span.duration',
- 'transaction',
- 'timestamp',
- ]); // default
-
- // try changing the field
- const input = within(section).getByRole('combobox', {
- name: 'Select an attribute',
- });
- await userEvent.click(input);
- await userEvent.click(within(section).getByRole('option', {name: 'span.self_time'}));
- await userEvent.keyboard('{Escape}');
-
- expect(fields).toEqual([
- 'id',
- 'span.op',
- 'span.description',
- 'span.duration',
- 'transaction',
- 'timestamp',
- 'span.self_time',
- ]);
-
- await userEvent.click(input);
- await userEvent.keyboard('{Backspace}');
-
- await userEvent.click(within(section).getByRole('option', {name: 'avg(\u2026)'}));
- await userEvent.click(within(section).getByRole('option', {name: 'span.self_time'}));
- await userEvent.keyboard('{Escape}');
- await userEvent.click(within(section).getByText('Visualize'));
-
- expect(visualizes).toEqual([new Visualize(['avg(span.self_time)'], {label: 'A'})]);
-
- // try adding a new chart
- await userEvent.click(within(section).getByRole('button', {name: 'Add Chart'}));
- expect(visualizes).toEqual([
- new Visualize(['avg(span.self_time)'], {label: 'A'}),
- new Visualize(['count(span.duration)'], {label: 'B'}),
- ]);
-
- // delete second chart
- await userEvent.click(within(section).getAllByLabelText('Remove Overlay')[1]!);
- expect(visualizes).toEqual([new Visualize(['avg(span.self_time)'], {label: 'A'})]);
-
- // only one left so cant be deleted
- expect(within(section).getByLabelText('Remove Overlay')).toBeDisabled();
- });
-
it('allows changing group bys', async function () {
let groupBys: any;
diff --git a/static/app/views/explore/toolbar/index.tsx b/static/app/views/explore/toolbar/index.tsx
index 4bf6b35a8e6b23..7b95d2786fba01 100644
--- a/static/app/views/explore/toolbar/index.tsx
+++ b/static/app/views/explore/toolbar/index.tsx
@@ -20,7 +20,7 @@ interface ExploreToolbarProps {
width?: number;
}
-export function ExploreToolbar({extras, width}: ExploreToolbarProps) {
+export function ExploreToolbar({width}: ExploreToolbarProps) {
const fields = useExploreFields();
const groupBys = useExploreGroupBys();
const visualizes = useExploreVisualizes();
@@ -29,7 +29,7 @@ export function ExploreToolbar({extras, width}: ExploreToolbarProps) {
return (
-
+
{visualize.yAxes.map((yAxis, index) => (
- {equationSupport ? (
-
- ) : (
-
- )}
+
))}
@@ -255,93 +235,6 @@ function VisualizeDropdown({
);
}
-interface VisualizeEquationProps {
- canDelete: boolean;
- deleteOverlay: (group: number, index: number) => void;
- group: number;
- index: number;
- setVisualizes: (visualizes: BaseVisualize[], fields?: string[]) => void;
- visualizes: Visualize[];
- label?: string;
- yAxis?: string;
-}
-
-function VisualizeEquation({
- canDelete,
- deleteOverlay,
- group,
- index,
- setVisualizes,
- label,
- yAxis,
- visualizes,
-}: VisualizeEquationProps) {
- const setChartYAxis = useCallback(
- (expression: Expression) => {
- if (expression.isValid) {
- const functions = expression.tokens.filter(isTokenFunction);
- const newVisualizes = visualizes.map((visualize, i) => {
- if (i === group) {
- const yAxes = [...visualize.yAxes];
- yAxes[index] = expression.text;
- visualize = visualize.replace({yAxes});
- }
- return visualize.toJSON();
- });
- setVisualizes(
- newVisualizes,
- functions.flatMap(func => func.attributes.map(attr => attr.format()))
- );
- }
- },
- [group, index, setVisualizes, visualizes]
- );
-
- const aggregateFunctions = useMemo(() => {
- return ALLOWED_EXPLORE_VISUALIZE_AGGREGATES.map(aggregate => {
- return {
- name: aggregate,
- label: `${aggregate}(\u2026)`,
- };
- });
- }, []);
-
- const yAxes: string[] = useMemo(() => {
- return visualizes.flatMap(visualize => visualize.yAxes);
- }, [visualizes]);
-
- const fieldOptions: Array> = useVisualizeFields({yAxes, yAxis});
-
- const functionArguments = useMemo(() => {
- return fieldOptions.map(o => {
- return {
- name: o.value,
- label: o.label,
- };
- });
- }, [fieldOptions]);
-
- return (
-
- {label && {label}}
-
- }
- size="zero"
- disabled={!canDelete}
- onClick={() => deleteOverlay(group, index)}
- aria-label={t('Remove Overlay')}
- />
-
- );
-}
-
const ChartLabel = styled('div')`
background-color: ${p => p.theme.purple100};
border-radius: ${p => p.theme.borderRadius};