Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into lens/type-safe-migr…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
wylieconlon committed May 7, 2020
2 parents 7b3bea9 + 834e3bf commit 155eeea
Show file tree
Hide file tree
Showing 30 changed files with 614 additions and 491 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ module.exports = {
files: ['x-pack/plugins/lens/**/*.{js,ts,tsx}'],
rules: {
'react-hooks/exhaustive-deps': 'off',
'react-hooks/rules-of-hooks': 'off',
},
},
{
Expand Down
6 changes: 5 additions & 1 deletion test/common/services/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@
*/

import { format as formatUrl } from 'url';

import fs from 'fs';
import { Client } from '@elastic/elasticsearch';
import { CA_CERT_PATH } from '@kbn/dev-utils';

import { FtrProviderContext } from '../ftr_provider_context';

export function ElasticsearchProvider({ getService }: FtrProviderContext) {
const config = getService('config');

return new Client({
ssl: {
ca: fs.readFileSync(CA_CERT_PATH, 'utf-8'),
},
nodes: [formatUrl(config.get('servers.elasticsearch'))],
requestTimeout: config.get('timeouts.esRequestTimeout'),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export function LayerPanel(
}
) {
const dragDropContext = useContext(DragContext);
const [popoverState, setPopoverState] = useState<DimensionPopoverState>({
isOpen: false,
openId: null,
addingToGroupId: null,
});

const { framePublicAPI, layerId, activeVisualization, isOnlyLayer, onRemoveLayer } = props;
const datasourcePublicAPI = framePublicAPI.datasourceLayers[layerId];
if (!datasourcePublicAPI) {
Expand Down Expand Up @@ -74,12 +80,6 @@ export function LayerPanel(
dateRange: props.framePublicAPI.dateRange,
};

const [popoverState, setPopoverState] = useState<DimensionPopoverState>({
isOpen: false,
openId: null,
addingToGroupId: null,
});

const { groups } = activeVisualization.getConfiguration(layerVisualizationConfigProps);
const isEmptyLayer = !groups.some(d => d.accessors.length > 0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ export function InnerWorkspacePanel({
framePublicAPI.filters,
]);

useEffect(() => {
// reset expression error if component attempts to run it again
if (expression && localState.expressionBuildError) {
setLocalState(s => ({
...s,
expressionBuildError: undefined,
}));
}
}, [expression]);

function onDrop() {
if (suggestionForDraggedField) {
trackUiEvent('drop_onto_workspace');
Expand Down Expand Up @@ -174,16 +184,6 @@ export function InnerWorkspacePanel({
}

function renderVisualization() {
useEffect(() => {
// reset expression error if component attempts to run it again
if (expression && localState.expressionBuildError) {
setLocalState(s => ({
...s,
expressionBuildError: undefined,
}));
}
}, [expression]);

if (expression === null) {
return renderEmptyWorkspace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,17 @@ describe('IndexPattern Data Panel', () => {

it('should render a warning if there are no index patterns', () => {
const wrapper = shallowWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} currentIndexPatternId="" indexPatterns={{}} />
<IndexPatternDataPanel
{...defaultProps}
state={{
...initialState,
currentIndexPatternId: '',
indexPatterns: {},
}}
setState={jest.fn()}
dragDropContext={{ dragging: {}, setDragging: () => {} }}
changeIndexPattern={jest.fn()}
/>
);
expect(wrapper.find('[data-test-subj="indexPattern-no-indexpatterns"]')).toHaveLength(1);
});
Expand Down
87 changes: 43 additions & 44 deletions x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,21 +144,49 @@ export function IndexPatternDataPanel({
indexPatternList.map(x => `${x.title}:${x.timeFieldName}`).join(','),
]}
/>
<MemoizedDataPanel
currentIndexPatternId={currentIndexPatternId}
indexPatternRefs={indexPatternRefs}
indexPatterns={indexPatterns}
query={query}
dateRange={dateRange}
filters={filters}
dragDropContext={dragDropContext}
showEmptyFields={state.showEmptyFields}
onToggleEmptyFields={onToggleEmptyFields}
core={core}
data={data}
onChangeIndexPattern={onChangeIndexPattern}
existingFields={state.existingFields}
/>

{Object.keys(indexPatterns).length === 0 ? (
<EuiFlexGroup
gutterSize="m"
className="lnsInnerIndexPatternDataPanel"
direction="column"
responsive={false}
>
<EuiFlexItem grow={null}>
<EuiCallOut
data-test-subj="indexPattern-no-indexpatterns"
title={i18n.translate('xpack.lens.indexPattern.noPatternsLabel', {
defaultMessage: 'No index patterns',
})}
color="warning"
iconType="alert"
>
<p>
<FormattedMessage
id="xpack.lens.indexPattern.noPatternsDescription"
defaultMessage="Please create an index pattern or switch to another data source"
/>
</p>
</EuiCallOut>
</EuiFlexItem>
</EuiFlexGroup>
) : (
<MemoizedDataPanel
currentIndexPatternId={currentIndexPatternId}
indexPatternRefs={indexPatternRefs}
indexPatterns={indexPatterns}
query={query}
dateRange={dateRange}
filters={filters}
dragDropContext={dragDropContext}
showEmptyFields={state.showEmptyFields}
onToggleEmptyFields={onToggleEmptyFields}
core={core}
data={data}
onChangeIndexPattern={onChangeIndexPattern}
existingFields={state.existingFields}
/>
)}
</>
);
}
Expand Down Expand Up @@ -194,35 +222,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
onChangeIndexPattern: (newId: string) => void;
existingFields: IndexPatternPrivateState['existingFields'];
}) {
if (Object.keys(indexPatterns).length === 0) {
return (
<EuiFlexGroup
gutterSize="m"
className="lnsInnerIndexPatternDataPanel"
direction="column"
responsive={false}
>
<EuiFlexItem grow={null}>
<EuiCallOut
data-test-subj="indexPattern-no-indexpatterns"
title={i18n.translate('xpack.lens.indexPattern.noPatternsLabel', {
defaultMessage: 'No index patterns',
})}
color="warning"
iconType="alert"
>
<p>
<FormattedMessage
id="xpack.lens.indexPattern.noPatternsDescription"
defaultMessage="Please create an index pattern or switch to another data source"
/>
</p>
</EuiCallOut>
</EuiFlexItem>
</EuiFlexGroup>
);
}

const [localState, setLocalState] = useState<DataPanelState>({
nameFilter: '',
typeFilter: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function BucketNestingEditor({
defaultMessage: 'Entire data set',
}),
},
...aggColumns,
...aggColumns.map(({ value, text }) => ({ value, text })),
]}
value={prevColumn}
onChange={e => setColumns(nestColumn(layer.columnOrder, e.target.value, columnId))}
Expand Down
31 changes: 15 additions & 16 deletions x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,22 +251,6 @@ function FieldItemPopoverContents(props: State & FieldItemProps) {

const IS_DARK_THEME = core.uiSettings.get('theme:darkMode');
const chartTheme = IS_DARK_THEME ? EUI_CHARTS_THEME_DARK.theme : EUI_CHARTS_THEME_LIGHT.theme;

if (props.isLoading) {
return <EuiLoadingSpinner />;
} else if (
(!props.histogram || props.histogram.buckets.length === 0) &&
(!props.topValues || props.topValues.buckets.length === 0)
) {
return (
<EuiText size="s">
{i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', {
defaultMessage: 'No data to display.',
})}
</EuiText>
);
}

let histogramDefault = !!props.histogram;

const totalValuesCount =
Expand Down Expand Up @@ -309,6 +293,21 @@ function FieldItemPopoverContents(props: State & FieldItemProps) {

let title = <></>;

if (props.isLoading) {
return <EuiLoadingSpinner />;
} else if (
(!props.histogram || props.histogram.buckets.length === 0) &&
(!props.topValues || props.topValues.buckets.length === 0)
) {
return (
<EuiText size="s">
{i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', {
defaultMessage: 'No data to display.',
})}
</EuiText>
);
}

if (histogram && histogram.buckets.length && topValues && topValues.buckets.length) {
title = (
<EuiButtonGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import expect from '@kbn/expect';
import { estimateBucketSpanFactory } from '../bucket_span_estimator';
import { APICaller } from 'kibana/server';

import { ES_AGGREGATION } from '../../../common/constants/aggregation_types';

import { estimateBucketSpanFactory, BucketSpanEstimatorData } from './bucket_span_estimator';

// Mock callWithRequest with the ability to simulate returning different
// permission settings. On each call using `ml.privilegeCheck` we retrieve
Expand All @@ -14,7 +17,7 @@ import { estimateBucketSpanFactory } from '../bucket_span_estimator';
// sufficient permissions should be returned, the second time insufficient
// permissions.
const permissions = [false, true];
const callWithRequest = method => {
const callWithRequest: APICaller = (method: string) => {
return new Promise(resolve => {
if (method === 'ml.privilegeCheck') {
resolve({
Expand All @@ -28,34 +31,19 @@ const callWithRequest = method => {
return;
}
resolve({});
});
}) as Promise<any>;
};

const callWithInternalUser = () => {
const callWithInternalUser: APICaller = () => {
return new Promise(resolve => {
resolve({});
});
}) as Promise<any>;
};

// mock xpack_main plugin
function mockXpackMainPluginFactory(isEnabled = false, licenseType = 'platinum') {
return {
info: {
isAvailable: () => true,
feature: () => ({
isEnabled: () => isEnabled,
}),
license: {
getType: () => licenseType,
},
},
};
}

// mock configuration to be passed to the estimator
const formConfig = {
aggTypes: ['count'],
duration: {},
const formConfig: BucketSpanEstimatorData = {
aggTypes: [ES_AGGREGATION.COUNT],
duration: { start: 0, end: 1 },
fields: [null],
index: '',
query: {
Expand All @@ -64,58 +52,45 @@ const formConfig = {
must_not: [],
},
},
splitField: undefined,
timeField: undefined,
};

describe('ML - BucketSpanEstimator', () => {
it('call factory', () => {
expect(function() {
estimateBucketSpanFactory(callWithRequest, callWithInternalUser);
}).to.not.throwError('Not initialized.');
estimateBucketSpanFactory(callWithRequest, callWithInternalUser, false);
}).not.toThrow('Not initialized.');
});

it('call factory and estimator with security disabled', done => {
expect(function() {
const estimateBucketSpan = estimateBucketSpanFactory(
callWithRequest,
callWithInternalUser,
mockXpackMainPluginFactory()
true
);

estimateBucketSpan(formConfig).catch(catchData => {
expect(catchData).to.be('Unable to retrieve cluster setting search.max_buckets');
expect(catchData).toBe('Unable to retrieve cluster setting search.max_buckets');

done();
});
}).to.not.throwError('Not initialized.');
}).not.toThrow('Not initialized.');
});

it('call factory and estimator with security enabled and sufficient permissions.', done => {
it('call factory and estimator with security enabled.', done => {
expect(function() {
const estimateBucketSpan = estimateBucketSpanFactory(
callWithRequest,
callWithInternalUser,
mockXpackMainPluginFactory(true)
false
);
estimateBucketSpan(formConfig).catch(catchData => {
expect(catchData).to.be('Unable to retrieve cluster setting search.max_buckets');
expect(catchData).toBe('Unable to retrieve cluster setting search.max_buckets');

done();
});
}).to.not.throwError('Not initialized.');
});

it('call factory and estimator with security enabled and insufficient permissions.', done => {
expect(function() {
const estimateBucketSpan = estimateBucketSpanFactory(
callWithRequest,
callWithInternalUser,
mockXpackMainPluginFactory(true)
);

estimateBucketSpan(formConfig).catch(catchData => {
expect(catchData).to.be('Insufficient permissions to call bucket span estimation.');
done();
});
}).to.not.throwError('Not initialized.');
}).not.toThrow('Not initialized.');
});
});
Loading

0 comments on commit 155eeea

Please sign in to comment.