De-angularize and EUI-ficate Discover Context control elements (#44474)
* Create ActionBar component, merges loading button and size picker * Use react component, remove angular code * Migrate constants + state to typescript * Remove unused increaseCount functions + tests * Add jest test
This commit is contained in:
parent
b57824f137
commit
3798674043
|
@ -81,11 +81,9 @@ query status and results.
|
|||
**query_parameters**: Exports the actions, reducers and selectors related to
|
||||
the parameters used to construct the query.
|
||||
|
||||
**components/loading_button**: Defines the `<context-loading-button>`
|
||||
**components/action_bar**: Defines the `<context-action-bar>`
|
||||
directive including its respective styles.
|
||||
|
||||
**components/size_picker**: Defines the `<context-size-picker>`
|
||||
directive including its respective styles.
|
||||
|
||||
**api/anchor.js**: Exports `fetchAnchor()` that creates and executes the
|
||||
query for the anchor document.
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
// cxtChart__legend--small
|
||||
// cxtChart__legend-isLoading
|
||||
|
||||
@import 'components/size_picker/index';
|
||||
@import 'components/action_bar/index';
|
||||
|
|
|
@ -62,48 +62,19 @@
|
|||
ng-if="contextApp.state.loadingStatus.anchor.status !== contextApp.constants.LOADING_STATUS.FAILED"
|
||||
>
|
||||
<!-- Controls -->
|
||||
<div class="kuiBar kuiVerticalRhythm">
|
||||
<div class="kuiBarSection">
|
||||
<context-loading-button
|
||||
data-test-subj="predecessorLoadMoreButton"
|
||||
is-disabled="![
|
||||
contextApp.constants.LOADING_STATUS.LOADED,
|
||||
contextApp.constants.LOADING_STATUS.FAILED,
|
||||
].includes(contextApp.state.loadingStatus.predecessors.status)"
|
||||
icon="'fa-chevron-up'"
|
||||
ng-click="contextApp.actions.fetchMorePredecessorRows()"
|
||||
>
|
||||
<span
|
||||
i18n-id="kbn.context.loadMoreDescription"
|
||||
i18n-default-message="Load {defaultStepSize} more"
|
||||
i18n-values="{
|
||||
defaultStepSize: contextApp.state.queryParameters.defaultStepSize
|
||||
}"
|
||||
></span>
|
||||
</context-loading-button>
|
||||
<context-size-picker
|
||||
count="contextApp.state.queryParameters.predecessorCount"
|
||||
data-test-subj="predecessorCountPicker"
|
||||
<context-action-bar
|
||||
default-step-size="contextApp.state.queryParameters.defaultStepSize"
|
||||
doc-count="contextApp.state.queryParameters.predecessorCount"
|
||||
doc-count-available="contextApp.state.rows.predecessors.length"
|
||||
is-disabled="contextApp.state.loadingStatus.anchor.status !== contextApp.constants.LOADING_STATUS.LOADED"
|
||||
is-loading="![
|
||||
contextApp.constants.LOADING_STATUS.LOADED,
|
||||
contextApp.constants.LOADING_STATUS.FAILED,
|
||||
].includes(contextApp.state.loadingStatus.predecessors.status)"
|
||||
on-change-count="contextApp.actions.fetchGivenPredecessorRows"
|
||||
></context-size-picker>
|
||||
<span
|
||||
i18n-id="kbn.context.newerDocumentsDescription"
|
||||
i18n-default-message="newer documents"
|
||||
></span>
|
||||
<span
|
||||
class="kuiStatusText kuiStatusText--warning"
|
||||
ng-if="(contextApp.state.loadingStatus.predecessors.status === contextApp.constants.LOADING_STATUS.LOADED)
|
||||
&& (contextApp.state.queryParameters.predecessorCount > contextApp.state.rows.predecessors.length)"
|
||||
>
|
||||
<span class="kuiStatusText__icon kuiIcon fa-bolt"></span>
|
||||
<span ng-bind-template="Only {{ contextApp.state.rows.predecessors.length }} documents newer than the anchor could be found."></span>
|
||||
</span>
|
||||
</div>
|
||||
type="'predecessors'"
|
||||
></context-action-bar>
|
||||
|
||||
<div class="kuiBarSection">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading feedback -->
|
||||
<div
|
||||
|
@ -139,46 +110,16 @@
|
|||
</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<div class="kuiBar kuiVerticalRhythm">
|
||||
<div class="kuiBarSection">
|
||||
<context-loading-button
|
||||
data-test-subj="successorLoadMoreButton"
|
||||
is-disabled="![
|
||||
contextApp.constants.LOADING_STATUS.LOADED,
|
||||
contextApp.constants.LOADING_STATUS.FAILED,
|
||||
].includes(contextApp.state.loadingStatus.successors.status)"
|
||||
icon="'fa-chevron-down'"
|
||||
ng-click="contextApp.actions.fetchMoreSuccessorRows()"
|
||||
>
|
||||
<span
|
||||
i18n-id="kbn.context.loadMoreDescription"
|
||||
i18n-default-message="Load {defaultStepSize} more"
|
||||
i18n-values="{
|
||||
defaultStepSize: contextApp.state.queryParameters.defaultStepSize
|
||||
}"
|
||||
></span>
|
||||
</context-loading-button>
|
||||
<context-size-picker
|
||||
count="contextApp.state.queryParameters.successorCount"
|
||||
data-test-subj="successorCountPicker"
|
||||
is-disabled="contextApp.state.loadingStatus.anchor.status !== contextApp.constants.LOADING_STATUS.LOADED"
|
||||
on-change-count="contextApp.actions.fetchGivenSuccessorRows"
|
||||
></context-size-picker>
|
||||
<div
|
||||
i18n-id="kbn.context.olderDocumentsDescription"
|
||||
i18n-default-message="older documents"
|
||||
></div>
|
||||
<span
|
||||
class="kuiStatusText kuiStatusText--warning"
|
||||
ng-if="(contextApp.state.loadingStatus.successors.status === contextApp.constants.LOADING_STATUS.LOADED)
|
||||
&& (contextApp.state.queryParameters.successorCount > contextApp.state.rows.successors.length)"
|
||||
>
|
||||
<span class="kuiStatusText__icon kuiIcon fa-bolt"></span>
|
||||
<span ng-bind-template="Only {{ contextApp.state.rows.successors.length }} documents older than the anchor could be found."></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="kuiBarSection">
|
||||
</div>
|
||||
</div>
|
||||
<context-action-bar
|
||||
default-step-size="contextApp.state.queryParameters.defaultStepSize"
|
||||
doc-count="contextApp.state.queryParameters.successorCount"
|
||||
doc-count-available="contextApp.state.rows.successors.length"
|
||||
is-disabled="contextApp.state.loadingStatus.anchor.status !== contextApp.constants.LOADING_STATUS.LOADED"
|
||||
is-loading="![
|
||||
contextApp.constants.LOADING_STATUS.LOADED,
|
||||
contextApp.constants.LOADING_STATUS.FAILED,
|
||||
].includes(contextApp.state.loadingStatus.successors.status)"
|
||||
on-change-count="contextApp.actions.fetchGivenSuccessorRows"
|
||||
type="'successors'"
|
||||
></context-action-bar>
|
||||
</main>
|
||||
|
|
|
@ -22,8 +22,7 @@ import _ from 'lodash';
|
|||
import { callAfterBindingsWorkaround } from 'ui/compat';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import contextAppTemplate from './app.html';
|
||||
import './components/loading_button';
|
||||
import './components/size_picker/size_picker';
|
||||
import './components/action_bar';
|
||||
import { getFirstSortableField } from './api/utils/sorting';
|
||||
import {
|
||||
createInitialQueryParametersState,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.cxtSizePicker {
|
||||
text-align: center;
|
||||
width: $euiSize * 5;
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
appearance: none; // Hide increment and decrement buttons for type="number" input.
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import './action_bar';
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { ActionBar, ActionBarProps } from './action_bar';
|
||||
// @ts-ignore
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from '../../query_parameters/constants';
|
||||
|
||||
describe('Test Discover Context ActionBar for successor | predecessor records', () => {
|
||||
['successors', 'predecessors'].forEach(type => {
|
||||
const onChangeCount = jest.fn();
|
||||
const props = {
|
||||
defaultStepSize: 5,
|
||||
docCount: 20,
|
||||
docCountAvailable: 0,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
onChangeCount,
|
||||
type,
|
||||
} as ActionBarProps;
|
||||
const wrapper = mountWithIntl(<ActionBar {...props} />);
|
||||
|
||||
const input = findTestSubject(wrapper, `${type}CountPicker`);
|
||||
const btn = findTestSubject(wrapper, `${type}LoadMoreButton`);
|
||||
|
||||
test(`${type}: Load button click`, () => {
|
||||
btn.simulate('click');
|
||||
expect(onChangeCount).toHaveBeenCalledWith(25);
|
||||
});
|
||||
|
||||
test(`${type}: Load button click doesnt submit when MAX_CONTEXT_SIZE was reached`, () => {
|
||||
onChangeCount.mockClear();
|
||||
input.simulate('change', { target: { valueAsNumber: MAX_CONTEXT_SIZE } });
|
||||
btn.simulate('click');
|
||||
expect(onChangeCount).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test(`${type}: Count input change submits on blur`, () => {
|
||||
input.simulate('change', { target: { valueAsNumber: 123 } });
|
||||
input.simulate('blur');
|
||||
expect(onChangeCount).toHaveBeenCalledWith(123);
|
||||
});
|
||||
|
||||
test(`${type}: Count input change submits on return`, () => {
|
||||
input.simulate('change', { target: { valueAsNumber: 124 } });
|
||||
input.simulate('submit');
|
||||
expect(onChangeCount).toHaveBeenCalledWith(124);
|
||||
});
|
||||
|
||||
test(`${type}: Count input doesnt submits values higher than MAX_CONTEXT_SIZE `, () => {
|
||||
onChangeCount.mockClear();
|
||||
input.simulate('change', { target: { valueAsNumber: MAX_CONTEXT_SIZE + 1 } });
|
||||
input.simulate('submit');
|
||||
expect(onChangeCount).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test(`${type}: Count input doesnt submits values lower than MIN_CONTEXT_SIZE `, () => {
|
||||
onChangeCount.mockClear();
|
||||
input.simulate('change', { target: { valueAsNumber: MIN_CONTEXT_SIZE - 1 } });
|
||||
input.simulate('submit');
|
||||
expect(onChangeCount).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test(`${type}: Warning about limitation of additional records`, () => {
|
||||
if (type === 'predecessors') {
|
||||
expect(findTestSubject(wrapper, 'predecessorsWarningMsg').text()).toBe(
|
||||
'No documents newer than the anchor could be found.'
|
||||
);
|
||||
} else {
|
||||
expect(findTestSubject(wrapper, 'successorsWarningMsg').text()).toBe(
|
||||
'No documents older than the anchor could be found.'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiFieldNumber,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { ActionBarWarning } from './action_bar_warning';
|
||||
import { SurrDocType } from '../../api/context';
|
||||
import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from '../../query_parameters/constants';
|
||||
|
||||
export interface ActionBarProps {
|
||||
/**
|
||||
* the number of documents fetched initially and added when the load button is clicked
|
||||
*/
|
||||
defaultStepSize: number;
|
||||
/**
|
||||
* the number of docs to be displayed
|
||||
*/
|
||||
docCount: number;
|
||||
/**
|
||||
* the number of documents that are available
|
||||
* display warning when it's lower than docCount
|
||||
*/
|
||||
docCountAvailable: number;
|
||||
/**
|
||||
* is true while the anchor record is fetched
|
||||
*/
|
||||
isDisabled: boolean;
|
||||
/**
|
||||
* is true when list entries are fetched
|
||||
*/
|
||||
isLoading: boolean;
|
||||
/**
|
||||
* is triggered when the input containing count is changed
|
||||
* @param count
|
||||
*/
|
||||
onChangeCount: (count: number) => void;
|
||||
/**
|
||||
* can be `predecessors` or `successors`, usage in context:
|
||||
* predecessors action bar + records (these are newer records)
|
||||
* anchor record
|
||||
* successors records + action bar (these are older records)
|
||||
*/
|
||||
type: SurrDocType;
|
||||
}
|
||||
|
||||
export function ActionBar({
|
||||
defaultStepSize,
|
||||
docCount,
|
||||
docCountAvailable,
|
||||
isDisabled,
|
||||
isLoading,
|
||||
onChangeCount,
|
||||
type,
|
||||
}: ActionBarProps) {
|
||||
const showWarning = !isDisabled && !isLoading && docCountAvailable < docCount;
|
||||
const isSuccessor = type === 'successors';
|
||||
const [newDocCount, setNewDocCount] = useState(docCount);
|
||||
const isValid = (value: number) => value >= MIN_CONTEXT_SIZE && value <= MAX_CONTEXT_SIZE;
|
||||
const onSubmit = (ev: React.FormEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
if (newDocCount !== docCount && isValid(newDocCount)) {
|
||||
onChangeCount(newDocCount);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={onSubmit}>
|
||||
{isSuccessor && <EuiSpacer size="s" />}
|
||||
{isSuccessor && showWarning && <ActionBarWarning docCount={docCountAvailable} type={type} />}
|
||||
{isSuccessor && showWarning && <EuiSpacer size="s" />}
|
||||
<EuiFlexGroup direction="row" gutterSize="s" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj={`${type}LoadMoreButton`}
|
||||
iconType={isSuccessor ? 'arrowDown' : 'arrowUp'}
|
||||
isDisabled={isDisabled}
|
||||
isLoading={isLoading}
|
||||
onClick={() => {
|
||||
const value = newDocCount + defaultStepSize;
|
||||
if (isValid(value)) {
|
||||
setNewDocCount(value);
|
||||
onChangeCount(value);
|
||||
}
|
||||
}}
|
||||
flush="right"
|
||||
>
|
||||
<FormattedMessage id="kbn.context.loadButtonLabel" defaultMessage="Load" />
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormRow>
|
||||
<EuiFieldNumber
|
||||
aria-label={
|
||||
isSuccessor
|
||||
? i18n.translate('kbn.context.olderDocumentsAriaLabel', {
|
||||
defaultMessage: 'Number of older documents',
|
||||
})
|
||||
: i18n.translate('kbn.context.newerDocumentsAriaLabel', {
|
||||
defaultMessage: 'Number of newer documents',
|
||||
})
|
||||
}
|
||||
className="cxtSizePicker"
|
||||
data-test-subj={`${type}CountPicker`}
|
||||
disabled={isDisabled}
|
||||
min={MIN_CONTEXT_SIZE}
|
||||
max={MAX_CONTEXT_SIZE}
|
||||
onChange={ev => {
|
||||
setNewDocCount(ev.target.valueAsNumber);
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (newDocCount !== docCount && isValid(newDocCount)) {
|
||||
onChangeCount(newDocCount);
|
||||
}
|
||||
}}
|
||||
type="number"
|
||||
value={newDocCount >= 0 ? newDocCount : ''}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow displayOnly>
|
||||
{isSuccessor ? (
|
||||
<FormattedMessage
|
||||
id="kbn.context.olderDocumentsDescription"
|
||||
defaultMessage="older documents"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="kbn.context.newerDocumentsDescription"
|
||||
defaultMessage="newer documents"
|
||||
/>
|
||||
)}
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{!isSuccessor && showWarning && <ActionBarWarning docCount={docCountAvailable} type={type} />}
|
||||
{!isSuccessor && <EuiSpacer size="s" />}
|
||||
</form>
|
||||
);
|
||||
}
|
|
@ -16,5 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { wrapInI18nContext } from 'ui/i18n';
|
||||
import { ActionBar } from './action_bar';
|
||||
|
||||
import './size_picker';
|
||||
uiModules.get('apps/context').directive('contextActionBar', function(reactDirective: any) {
|
||||
return reactDirective(wrapInI18nContext(ActionBar));
|
||||
});
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { SurrDocType } from '../../api/context';
|
||||
|
||||
export function ActionBarWarning({ docCount, type }: { docCount: number; type: SurrDocType }) {
|
||||
if (type === 'predecessors') {
|
||||
return (
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
data-test-subj="predecessorsWarningMsg"
|
||||
iconType="bolt"
|
||||
title={
|
||||
docCount === 0 ? (
|
||||
<FormattedMessage
|
||||
id="kbn.context.newerDocumentsWarningZero"
|
||||
defaultMessage="No documents newer than the anchor could be found."
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="kbn.context.newerDocumentsWarning"
|
||||
defaultMessage="Only {docCount} documents newer than the anchor could be found."
|
||||
values={{ docCount }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
size="s"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
data-test-subj="successorsWarningMsg"
|
||||
iconType="bolt"
|
||||
title={
|
||||
docCount === 0 ? (
|
||||
<FormattedMessage
|
||||
id="kbn.context.olderDocumentsWarningZero"
|
||||
defaultMessage="No documents older than the anchor could be found."
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="kbn.context.olderDocumentsWarning"
|
||||
defaultMessage="Only {docCount} documents older than the anchor could be found."
|
||||
values={{ docCount }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
size="s"
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import './loading_button';
|
||||
import './action_bar_directive';
|
|
@ -1,12 +0,0 @@
|
|||
<button
|
||||
class="kuiButton kuiButton--basic kuiButton--iconText"
|
||||
ng-disabled="isDisabled"
|
||||
>
|
||||
<span class="kuiButton__inner">
|
||||
<span
|
||||
class="kuiButton__icon kuiIcon fa-spinner fa-spin"
|
||||
ng-class="isDisabled ? ['fa-spinner', 'fa-spin'] : [icon]"
|
||||
/>
|
||||
<span ng-transclude />
|
||||
</span>
|
||||
</button>
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
import contextLoadingButtonTemplate from './loading_button.html';
|
||||
|
||||
|
||||
const module = uiModules.get('apps/context', [
|
||||
'kibana',
|
||||
'ngRoute',
|
||||
]);
|
||||
|
||||
module.directive('contextLoadingButton', function ContextLoadingButton() {
|
||||
return {
|
||||
replace: true,
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
isDisabled: '=',
|
||||
icon: '=',
|
||||
},
|
||||
template: contextLoadingButtonTemplate,
|
||||
transclude: true,
|
||||
};
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
@import './size_picker';
|
|
@ -1,14 +0,0 @@
|
|||
/**
|
||||
* 1. Hide increment and decrement buttons for type="number" input.
|
||||
*/
|
||||
.cxtSizePicker {
|
||||
appearance: textfield;
|
||||
text-align: center;
|
||||
width: $euiSize * 5;
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
appearance: none; /* 1 */
|
||||
margin: 0; /* 1 */
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<input
|
||||
class="kuiTextInput cxtSizePicker"
|
||||
ng-disabled="contextSizePicker.isDisabled"
|
||||
ng-model-options="{updateOn: 'change', getterSetter: true, debounce: 200}"
|
||||
ng-model="contextSizePicker.getOrSetCount"
|
||||
type="number"
|
||||
>
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { callAfterBindingsWorkaround } from 'ui/compat';
|
||||
import contextSizePickerTemplate from './size_picker.html';
|
||||
|
||||
const module = uiModules.get('apps/context', [
|
||||
'kibana',
|
||||
]);
|
||||
|
||||
module.directive('contextSizePicker', function ContextSizePicker() {
|
||||
return {
|
||||
bindToController: true,
|
||||
controller: callAfterBindingsWorkaround(ContextSizePickerController),
|
||||
controllerAs: 'contextSizePicker',
|
||||
link: linkContextSizePicker,
|
||||
replace: true,
|
||||
restrict: 'E',
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
count: '=',
|
||||
isDisabled: '=',
|
||||
onChangeCount: '=', // To avoid inconsistent ngModel states this action
|
||||
// should make sure the new value is propagated back
|
||||
// to the `count` property. If that propagation
|
||||
// fails, the user input will be reset to the value
|
||||
// of `count`.
|
||||
},
|
||||
template: contextSizePickerTemplate,
|
||||
};
|
||||
});
|
||||
|
||||
function linkContextSizePicker(scope, element, attrs, ngModel) {
|
||||
scope.countModel = ngModel;
|
||||
}
|
||||
|
||||
function ContextSizePickerController($scope) {
|
||||
$scope.$watch(
|
||||
() => this.count,
|
||||
() => $scope.countModel.$rollbackViewValue(),
|
||||
);
|
||||
|
||||
this.getOrSetCount = (count) => (
|
||||
_.isUndefined(count) ? this.count : this.onChangeCount(count)
|
||||
);
|
||||
}
|
|
@ -32,8 +32,6 @@ export function QueryActionsProvider(Private, Promise) {
|
|||
const fetchAnchor = Private(fetchAnchorProvider);
|
||||
const { fetchSurroundingDocs } = Private(fetchContextProvider);
|
||||
const {
|
||||
increasePredecessorCount,
|
||||
increaseSuccessorCount,
|
||||
setPredecessorCount,
|
||||
setQueryParameters,
|
||||
setSuccessorCount,
|
||||
|
@ -173,16 +171,6 @@ export function QueryActionsProvider(Private, Promise) {
|
|||
return fetchSurroundingRows('successors', state);
|
||||
};
|
||||
|
||||
const fetchMorePredecessorRows = (state) => () => {
|
||||
increasePredecessorCount(state)();
|
||||
return fetchSurroundingRows('predecessors', state);
|
||||
};
|
||||
|
||||
const fetchMoreSuccessorRows = (state) => () => {
|
||||
increaseSuccessorCount(state)();
|
||||
return fetchSurroundingRows('successors', state);
|
||||
};
|
||||
|
||||
const setAllRows = (state) => (predecessorRows, anchorRow, successorRows) => (
|
||||
state.rows.all = [
|
||||
...(predecessorRows || []),
|
||||
|
@ -199,8 +187,6 @@ export function QueryActionsProvider(Private, Promise) {
|
|||
fetchContextRowsWithNewQueryParameters,
|
||||
fetchGivenPredecessorRows,
|
||||
fetchGivenSuccessorRows,
|
||||
fetchMorePredecessorRows,
|
||||
fetchMoreSuccessorRows,
|
||||
setAllRows,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
|
||||
import { createStateStub } from './_utils';
|
||||
import { QueryParameterActionsProvider } from '../actions';
|
||||
|
||||
|
||||
describe('context app', function () {
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
describe('action increasePredecessorCount', function () {
|
||||
let increasePredecessorCount;
|
||||
|
||||
beforeEach(ngMock.inject(function createPrivateStubs(Private) {
|
||||
increasePredecessorCount = Private(QueryParameterActionsProvider).increasePredecessorCount;
|
||||
}));
|
||||
|
||||
it('should increase the predecessorCount by the given value', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increasePredecessorCount(state)(20);
|
||||
|
||||
expect(state.queryParameters.predecessorCount).to.equal(30);
|
||||
});
|
||||
|
||||
it('should increase the predecessorCount by the default step size if not value is given', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increasePredecessorCount(state)();
|
||||
|
||||
expect(state.queryParameters.predecessorCount).to.equal(13);
|
||||
});
|
||||
|
||||
it('should limit the predecessorCount to 0 as a lower bound', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increasePredecessorCount(state)(-20);
|
||||
|
||||
expect(state.queryParameters.predecessorCount).to.equal(0);
|
||||
});
|
||||
|
||||
it('should limit the predecessorCount to 10000 as an upper bound', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increasePredecessorCount(state)(20000);
|
||||
|
||||
expect(state.queryParameters.predecessorCount).to.equal(10000);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
|
||||
import { createStateStub } from './_utils';
|
||||
import { QueryParameterActionsProvider } from '../actions';
|
||||
|
||||
|
||||
describe('context app', function () {
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
describe('action increaseSuccessorCount', function () {
|
||||
let increaseSuccessorCount;
|
||||
|
||||
beforeEach(ngMock.inject(function createPrivateStubs(Private) {
|
||||
increaseSuccessorCount = Private(QueryParameterActionsProvider).increaseSuccessorCount;
|
||||
}));
|
||||
|
||||
it('should increase the successorCount by the given value', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increaseSuccessorCount(state)(20);
|
||||
|
||||
expect(state.queryParameters.successorCount).to.equal(30);
|
||||
});
|
||||
|
||||
it('should increase the successorCount by the default step size if not value is given', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increaseSuccessorCount(state)();
|
||||
|
||||
expect(state.queryParameters.successorCount).to.equal(13);
|
||||
});
|
||||
|
||||
it('should limit the successorCount to 0 as a lower bound', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increaseSuccessorCount(state)(-20);
|
||||
|
||||
expect(state.queryParameters.successorCount).to.equal(0);
|
||||
});
|
||||
|
||||
it('should limit the successorCount to 10000 as an upper bound', function () {
|
||||
const state = createStateStub();
|
||||
|
||||
increaseSuccessorCount(state)(20000);
|
||||
|
||||
expect(state.queryParameters.successorCount).to.equal(10000);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -40,12 +40,6 @@ export function QueryParameterActionsProvider(indexPatterns, Private) {
|
|||
)
|
||||
);
|
||||
|
||||
const increasePredecessorCount = (state) => (
|
||||
value = state.queryParameters.defaultStepSize,
|
||||
) => (
|
||||
setPredecessorCount(state)(state.queryParameters.predecessorCount + value)
|
||||
);
|
||||
|
||||
const setSuccessorCount = (state) => (successorCount) => (
|
||||
state.queryParameters.successorCount = clamp(
|
||||
MIN_CONTEXT_SIZE,
|
||||
|
@ -54,12 +48,6 @@ export function QueryParameterActionsProvider(indexPatterns, Private) {
|
|||
)
|
||||
);
|
||||
|
||||
const increaseSuccessorCount = (state) => (
|
||||
value = state.queryParameters.defaultStepSize,
|
||||
) => (
|
||||
setSuccessorCount(state)(state.queryParameters.successorCount + value)
|
||||
);
|
||||
|
||||
const setQueryParameters = (state) => (queryParameters) => (
|
||||
Object.assign(
|
||||
state.queryParameters,
|
||||
|
@ -82,8 +70,6 @@ export function QueryParameterActionsProvider(indexPatterns, Private) {
|
|||
return {
|
||||
addFilter,
|
||||
updateFilters,
|
||||
increasePredecessorCount,
|
||||
increaseSuccessorCount,
|
||||
setPredecessorCount,
|
||||
setQueryParameters,
|
||||
setSuccessorCount,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
import { createInitialQueryParametersState } from './state';
|
||||
|
||||
|
||||
export const MAX_CONTEXT_SIZE = 10000; // Elasticsearch's default maximum size limit
|
||||
export const MIN_CONTEXT_SIZE = 0;
|
||||
export const QUERY_PARAMETER_KEYS = Object.keys(createInitialQueryParametersState());
|
|
@ -17,7 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export function createInitialQueryParametersState(defaultStepSize, tieBreakerField) {
|
||||
export function createInitialQueryParametersState(
|
||||
defaultStepSize: number = 5,
|
||||
tieBreakerField: string = '_doc'
|
||||
) {
|
||||
return {
|
||||
anchorId: null,
|
||||
columns: [],
|
|
@ -54,19 +54,19 @@ export function ContextPageProvider({ getService, getPageObjects }) {
|
|||
}
|
||||
|
||||
async getPredecessorCountPicker() {
|
||||
return await testSubjects.find('predecessorCountPicker');
|
||||
return await testSubjects.find('predecessorsCountPicker');
|
||||
}
|
||||
|
||||
async getSuccessorCountPicker() {
|
||||
return await testSubjects.find('successorCountPicker');
|
||||
return await testSubjects.find('successorsCountPicker');
|
||||
}
|
||||
|
||||
async getPredecessorLoadMoreButton() {
|
||||
return await testSubjects.find('predecessorLoadMoreButton');
|
||||
return await testSubjects.find('predecessorsLoadMoreButton');
|
||||
}
|
||||
|
||||
async getSuccessorLoadMoreButton() {
|
||||
return await testSubjects.find('successorLoadMoreButton');
|
||||
return await testSubjects.find('successorsLoadMoreButton');
|
||||
}
|
||||
|
||||
async clickPredecessorLoadMoreButton() {
|
||||
|
|
|
@ -1369,7 +1369,6 @@
|
|||
"kbn.context.failedToLoadAnchorDocumentDescription": "別ののドキュメントの読み込みに失敗しました",
|
||||
"kbn.context.failedToLoadAnchorDocumentErrorDescription": "別のドキュメントの読み込みに失敗しました。",
|
||||
"kbn.context.loadingDescription": "読み込み中…",
|
||||
"kbn.context.loadMoreDescription": "他 {defaultStepSize} を読み込む",
|
||||
"kbn.context.newerDocumentsDescription": "新しいドキュメント",
|
||||
"kbn.context.noSearchableTiebreakerFieldDescription": "インデックスパターン {indexPatternId} で検索可能なタイブレーカーフィールドが見つかりませんでした。高度な設定 {tieBreakerFields} tを変更してこのインデックスパターンの有効なフィールドを含めてください。",
|
||||
"kbn.context.olderDocumentsDescription": "古いドキュメント",
|
||||
|
|
|
@ -1369,7 +1369,6 @@
|
|||
"kbn.context.failedToLoadAnchorDocumentDescription": "无法加载该定位点文档",
|
||||
"kbn.context.failedToLoadAnchorDocumentErrorDescription": "无法加载定位点文档。",
|
||||
"kbn.context.loadingDescription": "正在加载……",
|
||||
"kbn.context.loadMoreDescription": "再加载 {defaultStepSize} 个",
|
||||
"kbn.context.newerDocumentsDescription": "较新文档",
|
||||
"kbn.context.noSearchableTiebreakerFieldDescription": "索引模式 {indexPatternId} 中找不到任何可搜索的平分决胜字段。请更改高级设置“{tieBreakerFields}”以包括此索引模式的有效字段。",
|
||||
"kbn.context.olderDocumentsDescription": "较旧文档",
|
||||
|
|
Loading…
Reference in a new issue