Skip to content

Commit

Permalink
Web console: expose forceSegmentSortByTime (#16967)
Browse files Browse the repository at this point in the history
* no force time

* time UI

* update menus

* tweaks

* dont use bp5

* nicer values

* update snapshots

* similar engine lables

* update snaps
  • Loading branch information
vogievetsky authored Aug 29, 2024
1 parent 1d292c5 commit 358d06a
Show file tree
Hide file tree
Showing 21 changed files with 570 additions and 120 deletions.
2 changes: 1 addition & 1 deletion docs/operations/web-console.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ It is equivalent to the **Task** view in the **Ingestion** view with the filter
9. The **Preview** button appears when you enter an INSERT/REPLACE query. It runs the query inline without the INSERT/REPLACE clause and with an added LIMIT to give you a preview of the data that would be ingested if you click **Run**.
The added LIMIT makes the query run faster but provides incomplete results.
10. The engine selector lets you choose which engine (API endpoint) to send a query to. By default, it automatically picks which endpoint to use based on an analysis of the query, but you can select a specific engine explicitly. You can also configure the engine specific context parameters from this menu.
11. The **Max tasks** picker appears when you have the **sql-msq-task** engine selected. It lets you configure the degree of parallelism.
11. The **Max tasks** picker appears when you have the **SQL MSQ-task** engine selected. It lets you configure the degree of parallelism.
12. The More menu (**...**) contains the following helpful tools:
- **Explain SQL query** shows you the logical plan returned by `EXPLAIN PLAN FOR` for a SQL query.
- **Query history** shows you previously executed queries.
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/tutorial-sql-query-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ In this section you run some queries using aggregate functions and perform some

![aggregate-query](../assets/tutorial-sql-aggregate-query.png)

7. Click **Engine: auto (sql-native)** to display the engine options—**native** for native (JSON-based) queries, **sql-native** for Druid SQL queries, and **sql-msq-task** for SQL-based ingestion.
7. Click **Engine: Auto (SQL native)** to display the engine options—**Native** for native (JSON-based) queries, **SQL native** for Druid SQL queries, and **SQL MSQ-task** for SQL-based ingestion.

Select **auto** to let Druid select the most efficient engine based on your query input.
Select **Auto** to let Druid select the most efficient engine based on your query input.

8. From the engine menu you can also edit the query context and turn off some query defaults.

Expand Down
2 changes: 1 addition & 1 deletion web-console/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export * from './json-collapse/json-collapse';
export * from './json-input/json-input';
export * from './learn-more/learn-more';
export * from './loader/loader';
export * from './menu-boolean/menu-boolean';
export * from './menu-checkbox/menu-checkbox';
export * from './menu-tristate/menu-tristate';
export * from './more-button/more-button';
export * from './plural-pair-if-needed/plural-pair-if-needed';
export * from './popover-text/popover-text';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MenuTristate matches snapshot false 1`] = `
exports[`MenuBoolean matches snapshot false 1`] = `
<li
class="bp5-submenu"
role="none"
Expand Down Expand Up @@ -54,7 +54,7 @@ exports[`MenuTristate matches snapshot false 1`] = `
</li>
`;

exports[`MenuTristate matches snapshot undefined 1`] = `
exports[`MenuBoolean matches snapshot no undefined 1`] = `
<li
class="bp5-submenu"
role="none"
Expand All @@ -68,7 +68,61 @@ exports[`MenuTristate matches snapshot undefined 1`] = `
aria-expanded="false"
aria-haspopup="menu"
class="bp5-menu-item menu-tristate"
label="auto (true)"
label="false"
role="none"
tabindex="-1"
>
<div
class="bp5-text-overflow-ellipsis bp5-fill"
>
hello
</div>
<span
class="bp5-menu-item-label"
>
false
</span>
<span
class="bp5-icon bp5-icon-caret-right bp5-submenu-icon"
>
<svg
data-icon="caret-right"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<title>
Open sub menu
</title>
<path
d="M220 160C220 163 218.6 165.6 216.6 167.4L216.6 167.4L136.6 237.4L136.6 237.4C134.8 239 132.6 240 130 240C124.4 240 120 235.6 120 230V90C120 84.4 124.4 80 130 80C132.6 80 134.8 81 136.6 82.6C136.6 82.6 136.6 82.6 136.6 82.6L216.6 152.6L216.6 152.6C218.6 154.4 220 157 220 160z"
fill-rule="evenodd"
style="transform-origin: center;"
transform="scale(0.05, -0.05) translate(-160, -160)"
/>
</svg>
</span>
</a>
</span>
</li>
`;

exports[`MenuBoolean matches snapshot undefined 1`] = `
<li
class="bp5-submenu"
role="none"
>
<span
class="bp5-popover-target"
role="menuitem"
tabindex="0"
>
<a
aria-expanded="false"
aria-haspopup="menu"
class="bp5-menu-item menu-tristate"
label="Auto (true)"
role="none"
tabindex="-1"
>
Expand All @@ -80,7 +134,7 @@ exports[`MenuTristate matches snapshot undefined 1`] = `
<span
class="bp5-menu-item-label"
>
auto (true)
Auto (true)
</span>
<span
class="bp5-icon bp5-icon-caret-right bp5-submenu-icon"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
import { render } from '@testing-library/react';
import React from 'react';

import { MenuTristate } from './menu-tristate';
import { MenuBoolean } from './menu-boolean';

describe('MenuTristate', () => {
describe('MenuBoolean', () => {
it('matches snapshot undefined', () => {
const menuCheckbox = (
<MenuTristate
<MenuBoolean
text="hello"
value={undefined}
showUndefined
undefinedEffectiveValue
onValueChange={() => {}}
/>
Expand All @@ -37,14 +38,21 @@ describe('MenuTristate', () => {

it('matches snapshot false', () => {
const menuCheckbox = (
<MenuTristate
<MenuBoolean
text="hello"
value={false}
showUndefined
undefinedEffectiveValue={false}
onValueChange={() => {}}
/>
);
const { container } = render(menuCheckbox);
expect(container.firstChild).toMatchSnapshot();
});

it('matches snapshot no undefined', () => {
const menuCheckbox = <MenuBoolean text="hello" value={false} onValueChange={() => {}} />;
const { container } = render(menuCheckbox);
expect(container.firstChild).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,71 @@
import type { MenuItemProps } from '@blueprintjs/core';
import { MenuItem } from '@blueprintjs/core';
import classNames from 'classnames';
import type { ReactNode } from 'react';
import React from 'react';

import { tickIcon } from '../../utils';

export interface MenuTristateProps extends Omit<MenuItemProps, 'label'> {
export type TrueFalseUndefined = 'true' | 'false' | 'undefined';

function toKey(value: boolean | undefined) {
return String(value) as TrueFalseUndefined;
}

const DEFAULT_OPTIONS_TEXT: Partial<Record<TrueFalseUndefined, string>> = { undefined: 'Auto' };

export const ENABLE_DISABLE_OPTIONS_TEXT: Partial<Record<TrueFalseUndefined, string>> = {
true: 'Enable',
false: 'Disable',
undefined: 'Auto',
};

export interface MenuBooleanProps extends Omit<MenuItemProps, 'label'> {
value: boolean | undefined;
onValueChange(value: boolean | undefined): void;
undefinedLabel?: string;
showUndefined?: boolean;
undefinedEffectiveValue?: boolean;
optionsText?: Partial<Record<TrueFalseUndefined, string>>;
optionsLabelElement?: Partial<Record<TrueFalseUndefined, ReactNode>>;
}

export function MenuTristate(props: MenuTristateProps) {
export function MenuBoolean(props: MenuBooleanProps) {
const {
value,
onValueChange,
undefinedLabel,
showUndefined,
undefinedEffectiveValue,
className,
shouldDismissPopover,
optionsText = DEFAULT_OPTIONS_TEXT,
optionsLabelElement = {},
...rest
} = props;
const effectiveValue = showUndefined ? value : value ?? undefinedEffectiveValue;
const shouldDismiss = shouldDismissPopover ?? false;

function formatValue(value: boolean | undefined): string {
return String(value ?? undefinedLabel ?? 'auto');
const s = toKey(value);
return optionsText[s] ?? s;
}

return (
<MenuItem
className={classNames('menu-tristate', className)}
shouldDismissPopover={shouldDismiss}
label={
formatValue(value) +
(typeof value === 'undefined' && typeof undefinedEffectiveValue === 'boolean'
? ` (${undefinedEffectiveValue})`
: '')
}
label={`${formatValue(effectiveValue)}${
typeof effectiveValue === 'undefined' && typeof undefinedEffectiveValue === 'boolean'
? ` (${formatValue(undefinedEffectiveValue)})`
: ''
}`}
{...rest}
>
{[undefined, true, false].map((v, i) => (
{(showUndefined ? [undefined, true, false] : [true, false]).map(v => (
<MenuItem
key={i}
icon={tickIcon(value === v)}
key={String(v)}
icon={tickIcon(effectiveValue === v)}
text={formatValue(v)}
labelElement={optionsLabelElement[toKey(v)]}
onClick={() => onValueChange(v)}
shouldDismissPopover={shouldDismiss}
/>
Expand Down
12 changes: 10 additions & 2 deletions web-console/src/druid-models/dimension-spec/dimension-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@

import type { Field } from '../../components';
import { filterMap, typeIsKnown } from '../../utils';
import type { SampleResponse } from '../../utils/sampler';
import type { SampleResponse, TimeColumnAction } from '../../utils/sampler';
import { getHeaderNamesFromSampleResponse } from '../../utils/sampler';
import { guessColumnTypeFromSampleResponse } from '../ingestion-spec/ingestion-spec';
import { TIME_COLUMN } from '../timestamp-spec/timestamp-spec';

export interface DimensionsSpec {
readonly dimensions?: (string | DimensionSpec)[];
readonly dimensionExclusions?: string[];
readonly spatialDimensions?: any[];
readonly includeAllDimensions?: boolean;
readonly useSchemaDiscovery?: boolean;
readonly forceSegmentSortByTime?: boolean;
}

export interface DimensionSpec {
Expand Down Expand Up @@ -61,6 +63,7 @@ export const DIMENSION_SPEC_FIELDS: Field<DimensionSpec>[] = [
type: 'string',
required: true,
suggestions: KNOWN_TYPES,
disabled: d => d.name === TIME_COLUMN,
},
{
name: 'createBitmapIndex',
Expand Down Expand Up @@ -163,8 +166,13 @@ export function getDimensionSpecs(
guessNumericStringsAsNumbers: boolean,
forceMvdInsteadOfArray: boolean,
hasRollup: boolean,
timeColumnAction: TimeColumnAction,
): (string | DimensionSpec)[] {
return filterMap(getHeaderNamesFromSampleResponse(sampleResponse, 'ignore'), h => {
return filterMap(getHeaderNamesFromSampleResponse(sampleResponse, timeColumnAction), h => {
if (h === TIME_COLUMN) {
return { type: 'long', name: h };
}

const columnTypeHint = columnTypeHints[h];
const guessedColumnType = guessColumnTypeFromSampleResponse(
sampleResponse,
Expand Down
Loading

0 comments on commit 358d06a

Please sign in to comment.