mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Replace Inspector's EuiPopover with EuiComboBox (#113566)
* Replacing EuiPopover with EuiComboBox * The combobox will help alleviate issues when the list of options is very long * Refactoring the Combobox to listen for change events * Added an onChange handler * Renamed the method to render the combobox * Commented out additional blocks of code before final refactor * Finished refactoring the Request Selector to use EUI Combobox * Removed three helper methods for the EUIPopover. * `togglePopover()` * `closePopover()` * `renderRequestDropdownItem()` * Removed the local state object and interface (no longer needed) * Renamed the const `options` to `selectedOptions` in `handleSelectd()` method to better reflect where the options array was coming from. * Updating tests and translations * Fixed the inspector functional test to use comboBox service * Removed two unused translations * Updating Combobox options to pass data-test-sub string * Updated two tests for Combobox single option * Updated the test expectations to the default string * Both tests were looking for a named string instead of a default message * Adding error handling to Inspector combobox * Checking for the item status code * Adding a " (failed)" message if the status code returns `2` * Updating test to look for "Chart_data" instead of "Chartdata" * Updating two tests to validate single combobox options * Added helper method to check default text against combobox options * Added helper method to get the selected combobox option * Checking two inspector instances using helpers * Adding a defensive check to helper method. * Correct a type error in test return * Adding back translated failLabel Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Nathan L Smith <smith@nlsmith.com>
This commit is contained in:
parent
3ebfb029a2
commit
dba055c654
7 changed files with 85 additions and 119 deletions
|
@ -13,118 +13,73 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiButtonEmpty,
|
||||
EuiContextMenuPanel,
|
||||
EuiContextMenuItem,
|
||||
EuiComboBox,
|
||||
EuiComboBoxOptionOption,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLoadingSpinner,
|
||||
EuiPopover,
|
||||
EuiTextColor,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { RequestStatus } from '../../../../common/adapters';
|
||||
import { Request } from '../../../../common/adapters/request/types';
|
||||
|
||||
interface RequestSelectorState {
|
||||
isPopoverOpen: boolean;
|
||||
}
|
||||
|
||||
interface RequestSelectorProps {
|
||||
requests: Request[];
|
||||
selectedRequest: Request;
|
||||
onRequestChanged: Function;
|
||||
onRequestChanged: (request: Request) => void;
|
||||
}
|
||||
|
||||
export class RequestSelector extends Component<RequestSelectorProps, RequestSelectorState> {
|
||||
export class RequestSelector extends Component<RequestSelectorProps> {
|
||||
static propTypes = {
|
||||
requests: PropTypes.array.isRequired,
|
||||
selectedRequest: PropTypes.object.isRequired,
|
||||
onRequestChanged: PropTypes.func,
|
||||
};
|
||||
|
||||
state = {
|
||||
isPopoverOpen: false,
|
||||
handleSelected = (selectedOptions: Array<EuiComboBoxOptionOption<string>>) => {
|
||||
const selectedOption = this.props.requests.find(
|
||||
(request) => request.id === selectedOptions[0].value
|
||||
);
|
||||
|
||||
if (selectedOption) {
|
||||
this.props.onRequestChanged(selectedOption);
|
||||
}
|
||||
};
|
||||
|
||||
togglePopover = () => {
|
||||
this.setState((prevState: RequestSelectorState) => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen,
|
||||
}));
|
||||
};
|
||||
renderRequestCombobox() {
|
||||
const options = this.props.requests.map((item) => {
|
||||
const hasFailed = item.status === RequestStatus.ERROR;
|
||||
const testLabel = item.name.replace(/\s+/, '_');
|
||||
|
||||
closePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: false,
|
||||
return {
|
||||
'data-test-subj': `inspectorRequestChooser${testLabel}`,
|
||||
label: hasFailed
|
||||
? `${item.name} ${i18n.translate('inspector.requests.failedLabel', {
|
||||
defaultMessage: ' (failed)',
|
||||
})}`
|
||||
: item.name,
|
||||
value: item.id,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
renderRequestDropdownItem = (request: Request, index: number) => {
|
||||
const hasFailed = request.status === RequestStatus.ERROR;
|
||||
const inProgress = request.status === RequestStatus.PENDING;
|
||||
|
||||
return (
|
||||
<EuiContextMenuItem
|
||||
key={index}
|
||||
icon={request === this.props.selectedRequest ? 'check' : 'empty'}
|
||||
onClick={() => {
|
||||
this.props.onRequestChanged(request);
|
||||
this.closePopover();
|
||||
}}
|
||||
toolTipContent={request.description}
|
||||
toolTipPosition="left"
|
||||
data-test-subj={`inspectorRequestChooser${request.name}`}
|
||||
>
|
||||
<EuiTextColor color={hasFailed ? 'danger' : 'default'}>
|
||||
{request.name}
|
||||
|
||||
{hasFailed && (
|
||||
<FormattedMessage id="inspector.requests.failedLabel" defaultMessage=" (failed)" />
|
||||
)}
|
||||
|
||||
{inProgress && (
|
||||
<EuiLoadingSpinner
|
||||
size="s"
|
||||
aria-label={i18n.translate('inspector.requests.requestInProgressAriaLabel', {
|
||||
defaultMessage: 'Request in progress',
|
||||
})}
|
||||
className="insRequestSelector__menuSpinner"
|
||||
/>
|
||||
)}
|
||||
</EuiTextColor>
|
||||
</EuiContextMenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
renderRequestDropdown() {
|
||||
const button = (
|
||||
<EuiButtonEmpty
|
||||
iconType="arrowDown"
|
||||
iconSide="right"
|
||||
size="s"
|
||||
onClick={this.togglePopover}
|
||||
<EuiComboBox
|
||||
data-test-subj="inspectorRequestChooser"
|
||||
>
|
||||
{this.props.selectedRequest.name}
|
||||
</EuiButtonEmpty>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
fullWidth={true}
|
||||
id="inspectorRequestChooser"
|
||||
button={button}
|
||||
isOpen={this.state.isPopoverOpen}
|
||||
closePopover={this.closePopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
repositionOnScroll
|
||||
>
|
||||
<EuiContextMenuPanel
|
||||
items={this.props.requests.map(this.renderRequestDropdownItem)}
|
||||
data-test-subj="inspectorRequestChooserMenuPanel"
|
||||
isClearable={false}
|
||||
onChange={this.handleSelected}
|
||||
options={options}
|
||||
prepend="Request"
|
||||
selectedOptions={[
|
||||
{
|
||||
label: this.props.selectedRequest.name,
|
||||
value: this.props.selectedRequest.id,
|
||||
},
|
||||
]}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
/>
|
||||
</EuiPopover>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -132,23 +87,8 @@ export class RequestSelector extends Component<RequestSelectorProps, RequestSele
|
|||
const { selectedRequest, requests } = this.props;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<strong>
|
||||
<FormattedMessage id="inspector.requests.requestLabel" defaultMessage="Request:" />
|
||||
</strong>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={true}>
|
||||
{requests.length <= 1 && (
|
||||
<div
|
||||
className="insRequestSelector__singleRequest"
|
||||
data-test-subj="inspectorRequestName"
|
||||
>
|
||||
{selectedRequest.name}
|
||||
</div>
|
||||
)}
|
||||
{requests.length > 1 && this.renderRequestDropdown()}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={true}>{requests.length && this.renderRequestCombobox()}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{selectedRequest.status !== RequestStatus.PENDING && (
|
||||
<EuiToolTip
|
||||
|
|
|
@ -53,9 +53,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await inspector.open();
|
||||
await testSubjects.click('inspectorRequestChooser');
|
||||
let foundZero = false;
|
||||
for (const subj of ['Documents', 'Total hits', 'Charts']) {
|
||||
for (const subj of ['Documents', 'Chart_data']) {
|
||||
await testSubjects.click(`inspectorRequestChooser${subj}`);
|
||||
if (testSubjects.exists('inspectorRequestDetailStatistics', { timeout: 500 })) {
|
||||
if (await testSubjects.exists('inspectorRequestDetailStatistics', { timeout: 500 })) {
|
||||
await testSubjects.click(`inspectorRequestDetailStatistics`);
|
||||
const requestStatsTotalHits = getHitCount(await inspector.getTableData());
|
||||
if (requestStatsTotalHits === '0') {
|
||||
|
|
|
@ -131,9 +131,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('should set the default query name if not given in the schema', async () => {
|
||||
const requests = await inspector.getRequestNames();
|
||||
const singleExampleRequest = await inspector.hasSingleRequest();
|
||||
const selectedExampleRequest = await inspector.getSelectedOption();
|
||||
|
||||
expect(requests).to.be('Unnamed request #0');
|
||||
expect(singleExampleRequest).to.be(true);
|
||||
expect(selectedExampleRequest).to.equal('Unnamed request #0');
|
||||
});
|
||||
|
||||
it('should log the request statistic', async () => {
|
||||
|
|
|
@ -16,6 +16,7 @@ export class InspectorService extends FtrService {
|
|||
private readonly flyout = this.ctx.getService('flyout');
|
||||
private readonly testSubjects = this.ctx.getService('testSubjects');
|
||||
private readonly find = this.ctx.getService('find');
|
||||
private readonly comboBox = this.ctx.getService('comboBox');
|
||||
|
||||
private async getIsEnabled(): Promise<boolean> {
|
||||
const ariaDisabled = await this.testSubjects.getAttribute('openInspectorButton', 'disabled');
|
||||
|
@ -206,20 +207,29 @@ export class InspectorService extends FtrService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns request name as the comma-separated string
|
||||
* Returns the selected option value from combobox
|
||||
*/
|
||||
public async getSelectedOption(): Promise<string> {
|
||||
await this.openInspectorRequestsView();
|
||||
const selectedOption = await this.comboBox.getComboBoxSelectedOptions(
|
||||
'inspectorRequestChooser'
|
||||
);
|
||||
|
||||
if (selectedOption.length !== 1) {
|
||||
return 'Combobox has multiple options';
|
||||
}
|
||||
|
||||
return selectedOption[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns request name as the comma-separated string from combobox
|
||||
*/
|
||||
public async getRequestNames(): Promise<string> {
|
||||
await this.openInspectorRequestsView();
|
||||
const requestChooserExists = await this.testSubjects.exists('inspectorRequestChooser');
|
||||
if (requestChooserExists) {
|
||||
await this.testSubjects.click('inspectorRequestChooser');
|
||||
const menu = await this.testSubjects.find('inspectorRequestChooserMenuPanel');
|
||||
const requestNames = await menu.getVisibleText();
|
||||
return requestNames.trim().split('\n').join(',');
|
||||
}
|
||||
|
||||
const singleRequest = await this.testSubjects.find('inspectorRequestName');
|
||||
return await singleRequest.getVisibleText();
|
||||
const comboBoxOptions = await this.comboBox.getOptionsList('inspectorRequestChooser');
|
||||
return comboBoxOptions.trim().split('\n').join(',');
|
||||
}
|
||||
|
||||
public getOpenRequestStatisticButton() {
|
||||
|
@ -233,4 +243,17 @@ export class InspectorService extends FtrService {
|
|||
public getOpenRequestDetailResponseButton() {
|
||||
return this.testSubjects.find('inspectorRequestDetailResponse');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the value equals the combobox options list
|
||||
* @param value default combobox single option text
|
||||
*/
|
||||
public async hasSingleRequest(
|
||||
value: string = "You've selected all available options"
|
||||
): Promise<boolean> {
|
||||
await this.openInspectorRequestsView();
|
||||
const comboBoxOptions = await this.comboBox.getOptionsList('inspectorRequestChooser');
|
||||
|
||||
return value === comboBoxOptions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4162,7 +4162,6 @@
|
|||
"inspector.requests.noRequestsLoggedTitle": "リクエストが記録されていません",
|
||||
"inspector.requests.requestFailedTooltipTitle": "リクエストに失敗しました",
|
||||
"inspector.requests.requestInProgressAriaLabel": "リクエストが進行中",
|
||||
"inspector.requests.requestLabel": "リクエスト:",
|
||||
"inspector.requests.requestsDescriptionTooltip": "データを収集したリクエストを表示します",
|
||||
"inspector.requests.requestsTitle": "リクエスト",
|
||||
"inspector.requests.requestSucceededTooltipTitle": "リクエスト成功",
|
||||
|
|
|
@ -4201,7 +4201,6 @@
|
|||
"inspector.requests.noRequestsLoggedTitle": "未记录任何请求",
|
||||
"inspector.requests.requestFailedTooltipTitle": "请求失败",
|
||||
"inspector.requests.requestInProgressAriaLabel": "进行中的请求",
|
||||
"inspector.requests.requestLabel": "请求:",
|
||||
"inspector.requests.requestsDescriptionTooltip": "查看已收集数据的请求",
|
||||
"inspector.requests.requestsTitle": "请求",
|
||||
"inspector.requests.requestSucceededTooltipTitle": "请求成功",
|
||||
|
|
|
@ -77,9 +77,12 @@ export default function ({ getPageObjects, getService }) {
|
|||
await inspector.close();
|
||||
|
||||
await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example');
|
||||
const gridExampleRequestNames = await inspector.getRequestNames();
|
||||
const singleExampleRequest = await inspector.hasSingleRequest();
|
||||
const selectedExampleRequest = await inspector.getSelectedOption();
|
||||
await inspector.close();
|
||||
expect(gridExampleRequestNames).to.equal('logstash-*');
|
||||
|
||||
expect(singleExampleRequest).to.be(true);
|
||||
expect(selectedExampleRequest).to.equal('logstash-*');
|
||||
});
|
||||
|
||||
it('should apply container state (time, query, filters) to embeddable when loaded', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue