[Index management] Add support in url for hidden toggle (#66715)

* First iteration of supporting hidden indices in indices table

Tests probably have broken

* Remove unused code

* Fix logic when calling get index endpoint with empty array

Also remove unused translations

* First iteration of new flag being passed in through URL

* Added includeHidden param to index management list view

This allows setting the value of the "inlcude hidden" toggle via
the url hash query param "includeHidden". Also added a test.

* Remove unused variable

* Revise data flow

The component toggle gets it's initial state form hash query
param and thereafter the toggle drives the state in the url.

* Fix typo

* Delete ts-ignore

* Slight update to test and comment placement for clarity

* Fix copy-pasta

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Jean-Louis Leysens 2020-05-21 14:23:17 +02:00 committed by GitHub
parent 65370c70d2
commit 66af6f86e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 4 deletions

View file

@ -22,7 +22,7 @@ import { WithAppDependencies, services } from './setup_environment';
const testBedConfig: TestBedConfig = {
store: () => indexManagementStore(services as any),
memoryRouter: {
initialEntries: [`${BASE_PATH}indices`],
initialEntries: [`${BASE_PATH}indices?includeHidden=true`],
componentRoutePath: `${BASE_PATH}:section(indices|templates)`,
},
doMountAsync: true,
@ -44,6 +44,8 @@ export interface IdxMgmtHomeTestBed extends TestBed<IdxMgmtTestSubjects> {
clickTemplateAt: (index: number) => void;
clickCloseDetailsButton: () => void;
clickActionMenu: (name: TemplateDeserialized['name']) => void;
getIncludeHiddenIndicesToggleStatus: () => boolean;
clickIncludeHiddenIndicesToggle: () => void;
};
}
@ -124,6 +126,17 @@ export const setup = async (): Promise<IdxMgmtHomeTestBed> => {
find('closeDetailsButton').simulate('click');
};
const clickIncludeHiddenIndicesToggle = () => {
const { find } = testBed;
find('indexTableIncludeHiddenIndicesToggle').simulate('click');
};
const getIncludeHiddenIndicesToggleStatus = () => {
const { find } = testBed;
const props = find('indexTableIncludeHiddenIndicesToggle').props();
return Boolean(props['aria-checked']);
};
const selectIndexDetailsTab = async (
tab: 'settings' | 'mappings' | 'stats' | 'edit_settings'
) => {
@ -149,6 +162,8 @@ export const setup = async (): Promise<IdxMgmtHomeTestBed> => {
clickTemplateAt,
clickCloseDetailsButton,
clickActionMenu,
getIncludeHiddenIndicesToggleStatus,
clickIncludeHiddenIndicesToggle,
},
};
};
@ -173,6 +188,7 @@ export type TestSubjects =
| 'noSettingsCallout'
| 'indicesList'
| 'indicesTab'
| 'indexTableIncludeHiddenIndicesToggle'
| 'indexTableIndexNameLink'
| 'reloadButton'
| 'reloadIndicesButton'

View file

@ -44,6 +44,18 @@ describe('<IndexManagementHome />', () => {
});
});
test('sets the hash query param base on include hidden indices toggle', () => {
const { actions } = testBed;
expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
expect(window.location.hash.includes('includeHidden=true')).toBe(true);
actions.clickIncludeHiddenIndicesToggle();
expect(window.location.hash.includes('includeHidden=true')).toBe(false);
// Note: this test modifies the shared location.hash state, we put it back the way it was
actions.clickIncludeHiddenIndicesToggle();
expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
expect(window.location.hash.includes('includeHidden=true')).toBe(true);
});
test('should set the correct app title', () => {
const { exists, find } = testBed;
expect(exists('appTitle')).toBe(true);

View file

@ -12,10 +12,11 @@ export function IndexList({
match: {
params: { filter },
},
location,
}) {
return (
<div className="im-snapshotTestSubject" data-test-subj="indicesList">
<IndexTable filterFromURI={filter} />
<IndexTable filterFromURI={filter} location={location} />
<DetailPanel />
</div>
);

View file

@ -8,6 +8,7 @@ import React, { Component, Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { Route } from 'react-router-dom';
import { parse } from 'query-string';
import {
EuiButton,
@ -93,10 +94,18 @@ export class IndexTable extends Component {
selectedIndicesMap: {},
};
}
componentDidMount() {
this.props.loadIndices();
this.interval = setInterval(this.props.reloadIndices, REFRESH_RATE_INDEX_LIST);
const { filterChanged, filterFromURI } = this.props;
const {
filterChanged,
filterFromURI,
showHiddenIndicesChanged,
showHiddenIndices,
location,
} = this.props;
if (filterFromURI) {
const decodedFilter = decodeURIComponent(filterFromURI);
@ -107,6 +116,13 @@ export class IndexTable extends Component {
this.setState({ filterError: e });
}
}
// Check if the we have the includeHidden query param
const { includeHidden } = parse((location && location.search) || '');
const nextValue = includeHidden === 'true';
if (nextValue !== showHiddenIndices) {
showHiddenIndicesChanged(nextValue);
}
}
componentWillUnmount() {
clearInterval(this.interval);
@ -460,6 +476,7 @@ export class IndexTable extends Component {
<EuiFlexItem grow={false}>
<EuiSwitch
id="checkboxShowHiddenIndices"
data-test-subj="indexTableIncludeHiddenIndicesToggle"
checked={showHiddenIndices}
onChange={event => showHiddenIndicesChanged(event.target.checked)}
label={

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { syncUrlHashQueryParam } from './sync_url_hash_query_param.js';

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as q from 'query-string';
import { Middleware } from 'redux';
// @ts-ignore
import { showHiddenIndicesChanged } from '../actions';
export const syncUrlHashQueryParam: Middleware = () => next => action => {
if (action.type === String(showHiddenIndicesChanged)) {
const { url, query } = q.parseUrl(window.location.hash);
if (action.payload.showHiddenIndices) {
query.includeHidden = 'true';
} else {
delete query.includeHidden;
}
window.location.hash = url + '?' + q.stringify(query);
}
next(action);
};

View file

@ -9,6 +9,7 @@ import thunk from 'redux-thunk';
import { defaultTableState } from './reducers/table_state';
import { getReducer } from './reducers/';
import { syncUrlHashQueryParam } from './middlewares';
export function indexManagementStore(services) {
const toggleNameToVisibleMap = {};
@ -16,7 +17,7 @@ export function indexManagementStore(services) {
toggleNameToVisibleMap[toggleExtension.name] = false;
});
const initialState = { tableState: { ...defaultTableState, toggleNameToVisibleMap } };
const enhancers = [applyMiddleware(thunk)];
const enhancers = [applyMiddleware(thunk, syncUrlHashQueryParam)];
window.__REDUX_DEVTOOLS_EXTENSION__ && enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
return createStore(getReducer(services), initialState, compose(...enhancers));