Skip to content

Commit

Permalink
Web console: Explore view QA with live data (apache#17234) (apache#17237
Browse files Browse the repository at this point in the history
)

* Explore view QA with live data

* update snapshots

* add t for preview also

* use pulse icon consistently
  • Loading branch information
vogievetsky authored Oct 4, 2024
1 parent feae7f7 commit 84aec7a
Show file tree
Hide file tree
Showing 24 changed files with 1,018 additions and 888 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export const ControlPane = function ControlPane(props: ControlPaneProps) {
: filterMap(effectiveValue as ExpressionMeta[], ({ expression }) =>
expression instanceof SqlColumn ? expression.getName() : undefined,
);

return {
element: (
<NamedExpressionsInput<ExpressionMeta>
Expand Down Expand Up @@ -295,6 +296,10 @@ export const ControlPane = function ControlPane(props: ControlPaneProps) {
}

case 'measures': {
const disabledMeasureNames = parameter.allowDuplicates
? []
: filterMap(effectiveValue as Measure[], measure => measure.getAggregateMeasureName());

return {
element: (
<NamedExpressionsInput<Measure>
Expand All @@ -307,6 +312,7 @@ export const ControlPane = function ControlPane(props: ControlPaneProps) {
columns={columns}
measures={measures}
initMeasure={initMeasure}
disabledMeasureNames={disabledMeasureNames}
onSelectMeasure={m => onValueChange(changeOrAdd(effectiveValue, initMeasure, m))}
onClose={onClose}
onAddToSourceQueryAsMeasure={onAddToSourceQueryAsMeasure}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,25 @@ export interface MeasureMenuProps {
columns: readonly Column[];
measures: readonly Measure[];
initMeasure: Measure | undefined;
disabledMeasureNames?: string[];
onSelectMeasure(measure: Measure): void;
onClose(): void;
onAddToSourceQueryAsMeasure?(measure: Measure): void;
}

export const MeasureMenu = function MeasureMenu(props: MeasureMenuProps) {
const { columns, measures, initMeasure, onSelectMeasure, onClose, onAddToSourceQueryAsMeasure } =
props;
const {
columns,
measures,
initMeasure,
disabledMeasureNames = [],
onSelectMeasure,
onClose,
onAddToSourceQueryAsMeasure,
} = props;

const [tab, setTab] = useState<MeasureMenuTab>(() => {
if (!initMeasure) return 'compose';
if (!initMeasure) return measures.length > 1 ? 'saved' : 'compose';
if (measures.some(measure => measure.equivalent(initMeasure))) return 'saved';
return MeasurePattern.fit(initMeasure.expression) ? 'compose' : 'sql';
});
Expand Down Expand Up @@ -165,8 +173,9 @@ export const MeasureMenu = function MeasureMenu(props: MeasureMenuProps) {
return (
<MenuItem
key={i}
icon={IconNames.NUMERICAL}
icon={IconNames.PULSE}
text={aggregateMeasure.name}
disabled={disabledMeasureNames.includes(measure.name)}
labelElement={
aggregateMeasure.equals(initMeasure) ? <Icon icon={IconNames.TICK} /> : undefined
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

import { FormGroup, InputGroup, Menu, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import type { ContainsFilterPattern, QueryResult } from '@druid-toolkit/query';
import { C, F, filterPatternToExpression, SqlExpression, SqlQuery } from '@druid-toolkit/query';
import type { ContainsFilterPattern, QueryResult, SqlQuery } from '@druid-toolkit/query';
import { C, F, filterPatternToExpression, SqlExpression } from '@druid-toolkit/query';
import React, { useMemo } from 'react';

import { useQueryManager } from '../../../../../../hooks';
Expand All @@ -43,14 +43,14 @@ export const ContainsFilterControl = React.memo(function ContainsFilterControl(

const previewQuery = useMemo(
() =>
SqlQuery.from(querySource.query)
.addSelect(F.cast(C(column), 'VARCHAR').as('c'), { addToGroupBy: 'end' })
.changeWhereExpression(
querySource
.getInitQuery(
SqlExpression.and(
filter,
contains ? filterPatternToExpression(filterPattern) : undefined,
),
)
.addSelect(F.cast(C(column), 'VARCHAR').as('c'), { addToGroupBy: 'end' })
.changeOrderByExpression(F.count().toOrderByExpression('DESC'))
.changeLimitValue(101)
.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

import { FormGroup, InputGroup, Menu, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import type { QueryResult, RegexpFilterPattern } from '@druid-toolkit/query';
import { C, F, filterPatternToExpression, SqlExpression, SqlQuery } from '@druid-toolkit/query';
import type { QueryResult, RegexpFilterPattern, SqlQuery } from '@druid-toolkit/query';
import { C, F, filterPatternToExpression, SqlExpression } from '@druid-toolkit/query';
import React, { useMemo } from 'react';

import { useQueryManager } from '../../../../../../hooks';
Expand Down Expand Up @@ -52,11 +52,11 @@ export const RegexpFilterControl = React.memo(function RegexpFilterControl(

const previewQuery = useMemo(
() =>
SqlQuery.from(querySource.query)
.addSelect(F.cast(C(column), 'VARCHAR').as('c'), { addToGroupBy: 'end' })
.changeWhereExpression(
querySource
.getInitQuery(
SqlExpression.and(filter, regexp ? filterPatternToExpression(filterPattern) : undefined),
)
.addSelect(F.cast(C(column), 'VARCHAR').as('c'), { addToGroupBy: 'end' })
.changeOrderByExpression(F.count().toOrderByExpression('DESC'))
.changeLimitValue(101)
.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

import { FormGroup, Menu, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import type { QueryResult, ValuesFilterPattern } from '@druid-toolkit/query';
import { C, F, SqlExpression, SqlQuery } from '@druid-toolkit/query';
import type { QueryResult, SqlQuery, ValuesFilterPattern } from '@druid-toolkit/query';
import { C, F, SqlExpression } from '@druid-toolkit/query';
import React, { useMemo, useState } from 'react';

import { ClearableInput } from '../../../../../../components';
Expand Down Expand Up @@ -49,14 +49,14 @@ export const ValuesFilterControl = React.memo(function ValuesFilterControl(

const valuesQuery = useMemo(
() =>
SqlQuery.from(querySource.query)
.addSelect(C(column).as('c'), { addToGroupBy: 'end' })
.changeWhereExpression(
querySource
.getInitQuery(
SqlExpression.and(
filter,
searchString ? F('ICONTAINS_STRING', C(column), searchString) : undefined,
),
)
.addSelect(C(column).as('c'), { addToGroupBy: 'end' })
.changeOrderByExpression(F.count().toOrderByExpression('DESC'))
.changeLimitValue(101)
.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
text-overflow: ellipsis;
padding: 1px 0;
opacity: 0.8;

&.special {
font-style: italic;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
import { Callout } from '@blueprintjs/core';
import type { SqlQuery } from '@druid-toolkit/query';
import { type QueryResult } from '@druid-toolkit/query';
import classNames from 'classnames';
import React from 'react';

import { useQueryManager } from '../../../../hooks';
import { formatEmpty } from '../../../../utils';

import './preview-pane.scss';

Expand Down Expand Up @@ -58,8 +60,11 @@ export const PreviewPane = React.memo(function PreviewPane(props: PreviewPanePro
<div className="preview-values-wrapper">
<div className="preview-values">
{previewValues.map((v, i) => (
<div className="preview-value" key={i}>
{String(v)}
<div
className={classNames('preview-value', { special: v == null || v === '' })}
key={i}
>
{formatEmpty(v)}
</div>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
*/

import { Button, Classes, Dialog, FormGroup, InputGroup, Intent, Tag } from '@blueprintjs/core';
import { type QueryResult, F, sql, SqlExpression, SqlQuery } from '@druid-toolkit/query';
import type { SqlQuery } from '@druid-toolkit/query';
import { type QueryResult, F, sql, SqlExpression } from '@druid-toolkit/query';
import React, { useMemo, useState } from 'react';

import { AppToaster } from '../../../../../singletons';
import { ExpressionMeta, QuerySource } from '../../../models';
import type { QuerySource } from '../../../models';
import { ExpressionMeta } from '../../../models';
import type { Rename } from '../../../utils';
import { PreviewPane } from '../../preview-pane/preview-pane';
import { SqlInput } from '../../sql-input/sql-input';
Expand All @@ -46,7 +48,8 @@ export const ColumnDialog = React.memo(function ColumnDialog(props: ColumnDialog
const previewQuery = useMemo(() => {
const expression = SqlExpression.maybeParse(formula);
if (!expression) return;
return SqlQuery.from(QuerySource.stripToBaseSource(querySource.query))
return querySource
.getInitBaseQuery()
.addSelect(F.cast(expression, 'VARCHAR').as('v'), { addToGroupBy: 'end' })
.applyIf(querySource.hasBaseTimeColumn(), q =>
q.addWhere(sql`MAX_DATA_TIME() - INTERVAL '14' DAY <= __time`),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ import {
Menu,
Tag,
} from '@blueprintjs/core';
import type { SqlExpression } from '@druid-toolkit/query';
import { type QueryResult, F, sql, SqlFunction, SqlQuery } from '@druid-toolkit/query';
import type { SqlExpression, SqlQuery } from '@druid-toolkit/query';
import { type QueryResult, F, sql, SqlFunction } from '@druid-toolkit/query';
import React, { useState } from 'react';

import { ClearableInput, Loader, MenuCheckbox } from '../../../../../components';
import { useQueryManager } from '../../../../../hooks';
import { caseInsensitiveContains, filterMap, pluralIfNeeded } from '../../../../../utils';
import { ExpressionMeta, QuerySource } from '../../../models';
import type { QuerySource } from '../../../models';
import { ExpressionMeta } from '../../../models';
import { toggle } from '../../../utils';

import './nested-column-dialog.scss';
Expand All @@ -60,7 +61,8 @@ export const NestedColumnDialog = React.memo(function NestedColumnDialog(
const [pathsState] = useQueryManager({
query: nestedColumn,
processQuery: async nestedColumn => {
const query = SqlQuery.from(QuerySource.stripToBaseSource(querySource.query))
const query = querySource
.getInitBaseQuery()
.addSelect(
SqlFunction.decorated('ARRAY_CONCAT_AGG', 'DISTINCT', [
F('JSON_PATHS', nestedColumn),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ function formatQuerySource(source: SqlQuery | undefined): string | JSX.Element {
if (!(source instanceof SqlQuery)) return 'No source selected';
const fromExpressions = source.getFromExpressions();
if (fromExpressions.length !== 1) return 'Multiple FROM expressions';
const fromExpression = fromExpressions[0];
if (!(fromExpression instanceof SqlTable)) return 'Complex FROM expression';
return fromExpression.getName();
const fromExpression = fromExpressions[0].getUnderlyingExpression();
if (fromExpression instanceof SqlTable) {
return fromExpression.getName();
} else if (fromExpression instanceof SqlQuery) {
return formatQuerySource(fromExpression);
} else {
return 'Complex FROM expression';
}
}

export interface SourcePaneProps {
Expand Down
5 changes: 4 additions & 1 deletion web-console/src/views/explore-view/explore-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ export class ExploreState {
if (!QuerySource.isSingleStarQuery(this.parsedSource)) return this; // Only trigger for `SELECT * FROM ...` queries
if (!this.where.equal(SqlLiteral.TRUE)) return this;

const timeColumn = columns.find(c => c.isTimeColumn());
// Either find the `__time::TIMESTAMP` column or use the first column if it is a TIMESTAMP
const timeColumn =
columns.find(c => c.isTimeColumn()) ||
(columns[0].sqlType === 'TIMESTAMP' ? columns[0] : undefined);
if (!timeColumn) return this;

return this.change({
Expand Down
2 changes: 1 addition & 1 deletion web-console/src/views/explore-view/explore-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export const ExploreView = React.memo(function ExploreView() {
});

// -------------------------------------------------------
// If we have a __time::TIMESTAMP column and no filter add a filter
// If we have a TIMESTAMP column and no filter add a filter

useEffect(() => {
const columns = querySourceState.data?.columns;
Expand Down
4 changes: 4 additions & 0 deletions web-console/src/views/explore-view/models/measure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ export class Measure extends ExpressionMeta {
return this.changeExpression(F(Measure.AGGREGATE, L(this.name)));
}

public getAggregateMeasureName(): string | undefined {
return Measure.getAggregateMeasureName(this.expression);
}

public getUsedAggregates(): string[] {
return uniq(
filterMap(
Expand Down
8 changes: 8 additions & 0 deletions web-console/src/views/explore-view/models/query-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ export class QuerySource {
};
}

public getInitQuery(where?: SqlExpression): SqlQuery {
return SqlQuery.from(this.query.as('t')).changeWhereExpression(where);
}

public getInitBaseQuery(): SqlQuery {
return SqlQuery.from(QuerySource.stripToBaseSource(this.query).as('t'));
}

private materializeStarIfNeeded(): SqlQuery {
const { query, columns, measures } = this;
let columnsToExpand = columns.map(c => c.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* limitations under the License.
*/

import { L, SqlQuery } from '@druid-toolkit/query';
import { L } from '@druid-toolkit/query';
import type { ECharts } from 'echarts';
import * as echarts from 'echarts';
import React, { useEffect, useMemo, useRef } from 'react';
Expand Down Expand Up @@ -75,11 +75,10 @@ ModuleRepository.registerModule<BarChartParameterValues>({
const { splitColumn, measure, measureToSort, limit } = parameterValues;

const dataQuery = useMemo(() => {
const source = querySource.query;
const splitExpression = splitColumn ? splitColumn.expression : L(OVERALL_LABEL);

return SqlQuery.from(source)
.addWhere(where)
return querySource
.getInitQuery(where)
.addSelect(splitExpression.as('dim'), { addToGroupBy: 'end' })
.addSelect(measure.expression.as('met'), {
addToOrderBy: measureToSort ? undefined : 'end',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*/

import { Button } from '@blueprintjs/core';
import type { SqlExpression, SqlOrderByDirection } from '@druid-toolkit/query';
import { C, F, SqlQuery } from '@druid-toolkit/query';
import type { SqlExpression, SqlOrderByDirection, SqlQuery } from '@druid-toolkit/query';
import { C, F } from '@druid-toolkit/query';
import React, { useMemo } from 'react';

import { Loader } from '../../../components';
Expand Down Expand Up @@ -213,13 +213,14 @@ ModuleRepository.registerModule<GroupingTableParameterValues>({
const maxPivotValues = parameterValues.maxPivotValues || 10;
if (!pivotColumn) return;

return SqlQuery.from(querySource.query)
return querySource
.getInitQuery(where)
.addSelect(pivotColumn.expression.as('v'), { addToGroupBy: 'end' })
.changeOrderByExpression(
(measures.length ? measures[0].expression : F.count()).toOrderByExpression('DESC'),
)
.changeLimitValue(maxPivotValues);
}, [querySource.query, parameterValues]);
}, [querySource, where, parameterValues]);

const [pivotValueState, queryManager] = useQueryManager({
query: pivotValueQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
* limitations under the License.
*/

import { C, F, L, SqlQuery } from '@druid-toolkit/query';
import type { SqlQuery } from '@druid-toolkit/query';
import { C, F, L } from '@druid-toolkit/query';
import type { ECharts } from 'echarts';
import * as echarts from 'echarts';
import React, { useEffect, useMemo, useRef } from 'react';
Expand Down Expand Up @@ -82,10 +83,8 @@ ModuleRepository.registerModule<MultiAxisChartParameterValues>({
const { measures } = parameterValues;

const dataQuery = useMemo(() => {
const source = querySource.query;

return SqlQuery.from(source)
.addWhere(where)
return querySource
.getInitQuery(where)
.addSelect(F.timeFloor(C(timeColumnName || '__time'), L(timeGranularity)).as('time'), {
addToGroupBy: 'end',
addToOrderBy: 'end',
Expand Down
Loading

0 comments on commit 84aec7a

Please sign in to comment.