Skip to content

Commit

Permalink
Web console: fix count aggregation input in the data loader (apache#1…
Browse files Browse the repository at this point in the history
…1485)

* add typeIs

* fix unused field in count metric

* better types

* typos

* work with readonly types

* factor out apply cancel buttons

* form editor

* selection type

* unsaved changes

* form editor spec

* tidy up sampler

* more menu controls

* update e2e test
  • Loading branch information
vogievetsky authored Aug 5, 2021
1 parent 60e3955 commit 257bc5c
Show file tree
Hide file tree
Showing 28 changed files with 1,032 additions and 776 deletions.
24 changes: 6 additions & 18 deletions web-console/e2e-tests/reindexing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,9 @@ function validateConnectLocalData(preview: string) {
',"namespace":"Talk"' +
',"page":"Talk:Oswald Tilghman"' +
',"user":"GELongstreet"' +
',"added":"36"' +
',"deleted":"0"' +
',"delta":"36"' +
',"cityName":null' +
',"countryIsoCode":null' +
',"countryName":null' +
',"regionIsoCode":null' +
',"regionName":null' +
',"metroCode":null' +
',"added":36' +
',"deleted":0' +
',"delta":36' +
'}',
);
const lastLine = lines[lines.length - 1];
Expand All @@ -153,15 +147,9 @@ function validateConnectLocalData(preview: string) {
',"namespace":"Main"' +
',"page":"Hapoel Katamon Jerusalem F.C."' +
',"user":"The Quixotic Potato"' +
',"added":"1"' +
',"deleted":"0"' +
',"delta":"1"' +
',"cityName":null' +
',"countryIsoCode":null' +
',"countryName":null' +
',"regionIsoCode":null' +
',"regionName":null' +
',"metroCode":null' +
',"added":1' +
',"deleted":0' +
',"delta":1' +
'}',
);
}
Expand Down
27 changes: 17 additions & 10 deletions web-console/src/components/auto-form/auto-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { SuggestibleInput, Suggestion } from '../suggestible-input/suggestible-i

import './auto-form.scss';

export type Functor<M, R> = R | ((model: M) => R);
export type Functor<M, R> = R | ((model: Partial<M>) => R);

export interface Field<M> {
name: string;
Expand Down Expand Up @@ -59,7 +59,7 @@ export interface Field<M> {
hide?: Functor<M, boolean>;
hideInMore?: Functor<M, boolean>;
valueAdjustment?: (value: any) => any;
adjustment?: (model: M) => M;
adjustment?: (model: Partial<M>) => Partial<M>;
issueWithValue?: (value: any) => string | undefined;
}

Expand All @@ -71,12 +71,12 @@ interface ComputedFieldValues {

export interface AutoFormProps<M> {
fields: Field<M>[];
model: M | undefined;
onChange: (newModel: M) => void;
model: Partial<M> | undefined;
onChange: (newModel: Partial<M>) => void;
onFinalize?: () => void;
showCustom?: (model: M) => boolean;
showCustom?: (model: Partial<M>) => boolean;
large?: boolean;
globalAdjustment?: (model: M) => M;
globalAdjustment?: (model: Partial<M>) => Partial<M>;
}

export interface AutoFormState {
Expand Down Expand Up @@ -111,7 +111,7 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent

static evaluateFunctor<M, R>(
functor: undefined | Functor<M, R>,
model: M | undefined,
model: Partial<M> | undefined,
defaultValue: R,
): R {
if (!model || functor == null) return defaultValue;
Expand All @@ -122,7 +122,14 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
}
}

static issueWithModel<M>(model: M | undefined, fields: readonly Field<M>[]): string | undefined {
static isValidModel<M>(model: Partial<M> | undefined, fields: readonly Field<M>[]): model is M {
return !AutoForm.issueWithModel(model, fields);
}

static issueWithModel<M>(
model: Partial<M> | undefined,
fields: readonly Field<M>[],
): string | undefined {
if (typeof model === 'undefined') {
return `model is undefined`;
}
Expand Down Expand Up @@ -179,7 +186,7 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
newValue = field.valueAdjustment(newValue);
}

let newModel: T;
let newModel: Partial<T>;
if (typeof newValue === 'undefined') {
if (typeof field.emptyValue === 'undefined') {
newModel = deepDelete(model, field.name);
Expand All @@ -197,7 +204,7 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
this.modelChange(newModel);
};

private readonly modelChange = (newModel: T) => {
private readonly modelChange = (newModel: Partial<T>) => {
const { globalAdjustment, fields, onChange, model } = this.props;

// Delete things that are not defined now (but were defined prior to the change)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ import './lookup-edit-dialog.scss';
export interface LookupEditDialogProps {
onClose: () => void;
onSubmit: (updateLookupVersion: boolean) => void;
onChange: (field: 'name' | 'tier' | 'version' | 'spec', value: string | LookupSpec) => void;
onChange: (
field: 'name' | 'tier' | 'version' | 'spec',
value: string | Partial<LookupSpec>,
) => void;
lookupName: string;
lookupTier: string;
lookupVersion: string;
lookupSpec: LookupSpec;
lookupSpec: Partial<LookupSpec>;
isEdit: boolean;
allLookupTiers: string[];
}
Expand Down
25 changes: 11 additions & 14 deletions web-console/src/druid-models/compaction-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.maxRowsPerSegment',
type: 'number',
defaultValue: 5000000,
defined: (t: CompactionConfig) => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'dynamic',
defined: t => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'dynamic',
info: <>Determines how many rows are in each segment.</>,
},
{
name: 'tuningConfig.partitionsSpec.maxTotalRows',
type: 'number',
defaultValue: 20000000,
defined: (t: CompactionConfig) => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'dynamic',
defined: t => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'dynamic',
info: <>Total number of rows in segments waiting for being pushed.</>,
},
// partitionsSpec type: hashed
Expand All @@ -71,7 +71,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
type: 'number',
zeroMeansUndefined: true,
placeholder: `(defaults to 500000)`,
defined: (t: CompactionConfig) =>
defined: t =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'hashed' &&
!deepGet(t, 'tuningConfig.partitionsSpec.numShards') &&
!deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment'),
Expand All @@ -92,7 +92,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.maxRowsPerSegment',
type: 'number',
zeroMeansUndefined: true,
defined: (t: CompactionConfig) =>
defined: t =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'hashed' &&
!deepGet(t, 'tuningConfig.partitionsSpec.numShards') &&
!deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment'),
Expand All @@ -113,7 +113,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.numShards',
type: 'number',
zeroMeansUndefined: true,
defined: (t: CompactionConfig) =>
defined: t =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'hashed' &&
!deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment') &&
!deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment'),
Expand All @@ -135,23 +135,22 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.partitionDimensions',
type: 'string-array',
placeholder: '(all dimensions)',
defined: (t: CompactionConfig) => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'hashed',
defined: t => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'hashed',
info: <p>The dimensions to partition on. Leave blank to select all dimensions.</p>,
},
// partitionsSpec type: single_dim
{
name: 'tuningConfig.partitionsSpec.partitionDimension',
type: 'string',
defined: (t: CompactionConfig) =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim',
defined: t => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim',
required: true,
info: <p>The dimension to partition on.</p>,
},
{
name: 'tuningConfig.partitionsSpec.targetRowsPerSegment',
type: 'number',
zeroMeansUndefined: true,
defined: (t: CompactionConfig) =>
defined: t =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim' &&
!deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment'),
required: (t: CompactionConfig) =>
Expand All @@ -168,7 +167,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.maxRowsPerSegment',
type: 'number',
zeroMeansUndefined: true,
defined: (t: CompactionConfig) =>
defined: t =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim' &&
!deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment'),
required: (t: CompactionConfig) =>
Expand All @@ -180,8 +179,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
name: 'tuningConfig.partitionsSpec.assumeGrouped',
type: 'boolean',
defaultValue: false,
defined: (t: CompactionConfig) =>
deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim',
defined: t => deepGet(t, 'tuningConfig.partitionsSpec.type') === 'single_dim',
info: (
<p>
Assume that input data has already been grouped on time and dimensions. Ingestion will run
Expand Down Expand Up @@ -223,8 +221,7 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
type: 'number',
defaultValue: 10,
min: 1,
defined: (t: CompactionConfig) =>
oneOf(deepGet(t, 'tuningConfig.partitionsSpec.type'), 'hashed', 'single_dim'),
defined: t => oneOf(deepGet(t, 'tuningConfig.partitionsSpec.type'), 'hashed', 'single_dim'),
info: <>Maximum number of merge tasks which can be run at the same time.</>,
},
{
Expand Down
19 changes: 11 additions & 8 deletions web-console/src/druid-models/dimension-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,41 @@
*/

import { Field } from '../components';
import { filterMap } from '../utils';
import { filterMap, typeIs } from '../utils';
import { HeaderAndRows } from '../utils/sampler';

import { getColumnTypeFromHeaderAndRows } from './ingestion-spec';

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

export interface DimensionSpec {
type: string;
name: string;
createBitmapIndex?: boolean;
readonly type: string;
readonly name: string;
readonly createBitmapIndex?: boolean;
}

export const DIMENSION_SPEC_FIELDS: Field<DimensionSpec>[] = [
{
name: 'name',
type: 'string',
required: true,
placeholder: 'dimension_name',
},
{
name: 'type',
type: 'string',
required: true,
suggestions: ['string', 'long', 'float', 'double'],
},
{
name: 'createBitmapIndex',
type: 'boolean',
defined: typeIs('string'),
defaultValue: true,
defined: (dimensionSpec: DimensionSpec) => dimensionSpec.type === 'string',
},
];

Expand Down
37 changes: 23 additions & 14 deletions web-console/src/druid-models/filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ import React from 'react';

import { ExternalLink, Field } from '../components';
import { getLink } from '../links';
import { deepGet, EMPTY_ARRAY, oneOf } from '../utils';
import { deepGet, EMPTY_ARRAY, oneOf, typeIs } from '../utils';

import { IngestionSpec } from './ingestion-spec';

export type DruidFilter = Record<string, any>;
export interface DruidFilter {
readonly type: string;
readonly [k: string]: any;
}

export interface DimensionFiltersWithRest {
dimensionFilters: DruidFilter[];
Expand Down Expand Up @@ -81,73 +84,79 @@ export const FILTER_FIELDS: Field<DruidFilter>[] = [
{
name: 'type',
type: 'string',
required: true,
suggestions: KNOWN_FILTER_TYPES,
},
{
name: 'dimension',
type: 'string',
defined: (df: DruidFilter) => oneOf(df.type, 'selector', 'in', 'interval', 'regex', 'like'),
defined: typeIs('selector', 'in', 'interval', 'regex', 'like'),
required: true,
},
{
name: 'value',
type: 'string',
defined: (df: DruidFilter) => df.type === 'selector',
defined: typeIs('selector'),
required: true,
},
{
name: 'values',
type: 'string-array',
defined: (df: DruidFilter) => df.type === 'in',
defined: typeIs('in'),
required: true,
},
{
name: 'intervals',
type: 'string-array',
defined: (df: DruidFilter) => df.type === 'interval',
defined: typeIs('interval'),
required: true,
placeholder: 'ex: 2020-01-01/2020-06-01',
},
{
name: 'pattern',
type: 'string',
defined: (df: DruidFilter) => oneOf(df.type, 'regex', 'like'),
defined: typeIs('regex', 'like'),
required: true,
},

{
name: 'field.type',
label: 'Sub-filter type',
type: 'string',
suggestions: ['selector', 'in', 'interval', 'regex', 'like'],
defined: (df: DruidFilter) => df.type === 'not',
defined: typeIs('not'),
required: true,
},
{
name: 'field.dimension',
label: 'Sub-filter dimension',
type: 'string',
defined: (df: DruidFilter) => df.type === 'not',
defined: typeIs('not'),
},
{
name: 'field.value',
label: 'Sub-filter value',
type: 'string',
defined: (df: DruidFilter) => df.type === 'not' && deepGet(df, 'field.type') === 'selector',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'selector',
},
{
name: 'field.values',
label: 'Sub-filter values',
type: 'string-array',
defined: (df: DruidFilter) => df.type === 'not' && deepGet(df, 'field.type') === 'in',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'in',
},
{
name: 'field.intervals',
label: 'Sub-filter intervals',
type: 'string-array',
defined: (df: DruidFilter) => df.type === 'not' && deepGet(df, 'field.type') === 'interval',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'interval',
placeholder: 'ex: 2020-01-01/2020-06-01',
},
{
name: 'field.pattern',
label: 'Sub-filter pattern',
type: 'string',
defined: (df: DruidFilter) =>
df.type === 'not' && oneOf(deepGet(df, 'field.type'), 'regex', 'like'),
defined: df => df.type === 'not' && oneOf(deepGet(df, 'field.type'), 'regex', 'like'),
},
];

Expand Down
Loading

0 comments on commit 257bc5c

Please sign in to comment.