Skip to content

Commit

Permalink
Add API endpoint for retrieving a single data stream. Add detail panel.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjcenizal committed Jun 23, 2020
1 parent 8abf4af commit f5ec8ca
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

import { DataStream, DataStreamFromEs } from '../types';

export function deserializeDataStreamList(dataStreamsFromEs: DataStreamFromEs[]): DataStream[] {
return dataStreamsFromEs.map(({ name, timestamp_field, indices, generation }) => ({
export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataStream {
const { name, timestamp_field, indices, generation } = dataStreamFromEs;

return {
name,
timeStampField: timestamp_field,
indices: indices.map(
Expand All @@ -17,5 +19,9 @@ export function deserializeDataStreamList(dataStreamsFromEs: DataStreamFromEs[])
})
),
generation,
}));
};
}

export function deserializeDataStreamList(dataStreamsFromEs: DataStreamFromEs[]): DataStream[] {
return dataStreamsFromEs.map((dataStream) => deserializeDataStream(dataStream));
}
2 changes: 1 addition & 1 deletion x-pack/plugins/index_management/common/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

export { deserializeDataStreamList } from './data_stream_serialization';
export { deserializeDataStream, deserializeDataStreamList } from './data_stream_serialization';

export {
deserializeLegacyTemplateList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment } from 'react';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiFlyout,
Expand All @@ -15,6 +15,9 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiDescriptionList,
EuiDescriptionListTitle,
EuiDescriptionListDescription,
} from '@elastic/eui';

import { SectionLoading, SectionError, Error } from '../../../../components';
Expand Down Expand Up @@ -61,7 +64,29 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
/>
);
} else if (dataStream) {
content = <Fragment>{JSON.stringify(dataStream)}</Fragment>;
const { timeStampField, generation } = dataStream;

content = (
<EuiDescriptionList textStyle="reverse">
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle"
defaultMessage="Timestamp field"
/>
</EuiDescriptionListTitle>

<EuiDescriptionListDescription>{timeStampField.name}</EuiDescriptionListDescription>

<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.idxMgmt.dataStreamDetailPanel.generationTitle"
defaultMessage="Generation"
/>
</EuiDescriptionListTitle>

<EuiDescriptionListDescription>{generation}</EuiDescriptionListDescription>
</EuiDescriptionList>
);
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import { reactRouterNavigate } from '../../../../shared_imports';
import { useAppContext } from '../../../app_context';
import { SectionError, SectionLoading, Error } from '../../../components';
import { useLoadDataStreams } from '../../../services/api';
import { decodePathFromReactRouter } from '../../../services/routing';
import { Section } from '../../home';
import { DataStreamTable } from './data_stream_table';
import { DataStreamDetailPanel } from './data_stream_detail_panel';

interface MatchParams {
dataStreamName?: string;
Expand Down Expand Up @@ -106,21 +109,22 @@ export const DataStreamList: React.FunctionComponent<RouteComponentProps<MatchPa
<EuiSpacer size="l" />

<DataStreamTable
filters={dataStreamName !== undefined ? `name=${dataStreamName}` : ''}
filters={
dataStreamName !== undefined ? `name=${decodePathFromReactRouter(dataStreamName)}` : ''
}
dataStreams={dataStreams}
reload={reload}
history={history as ScopedHistory}
/>

{/* TODO: Implement this once we have something to put in here, e.g. storage size, docs count */}
{/* dataStreamName && (
{dataStreamName && (
<DataStreamDetailPanel
dataStreamName={decodePathFromReactRouter(dataStreamName)}
onClose={() => {
history.push('/data_streams');
history.push(`/${Section.DataStreams}`);
}}
/>
)*/}
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ScopedHistory } from 'kibana/public';
import { DataStream } from '../../../../../../common/types';
import { reactRouterNavigate } from '../../../../../shared_imports';
import { encodePathForReactRouter } from '../../../../services/routing';
import { Section } from '../../../home';
import { DeleteDataStreamConfirmationModal } from '../delete_data_stream_confirmation_modal';

interface Props {
Expand All @@ -39,7 +40,19 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
}),
truncateText: true,
sortable: true,
// TODO: Render as a link to open the detail panel
render: (name: DataStream['name'], item: DataStream) => {
return (
/* eslint-disable-next-line @elastic/eui/href-or-on-click */
<EuiLink
{...reactRouterNavigate(history, {
pathname: `/${Section.DataStreams}/${encodePathForReactRouter(name)}`,
})}
data-test-subj="dataStreamDetailsLink"
>
{name}
</EuiLink>
);
},
},
{
field: 'indices',
Expand All @@ -62,22 +75,6 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
</EuiLink>
),
},
{
field: 'timeStampField.name',
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.timeStampFieldColumnTitle', {
defaultMessage: 'Timestamp field',
}),
truncateText: true,
sortable: true,
},
{
field: 'generation',
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.generationFieldColumnTitle', {
defaultMessage: 'Generation',
}),
truncateText: true,
sortable: true,
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.actionColumnTitle', {
defaultMessage: 'Actions',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ export function useLoadDataStreams() {
});
}

// TODO: Implement this API endpoint once we have content to surface in the detail panel.
export function useLoadDataStream(name: string) {
return useRequest<DataStream[]>({
path: `${API_BASE_PATH}/data_stream/${encodeURIComponent(name)}`,
return useRequest<DataStream>({
path: `${API_BASE_PATH}/data_streams/${encodeURIComponent(name)}`,
method: 'get',
});
}
Expand Down
14 changes: 14 additions & 0 deletions x-pack/plugins/index_management/server/client/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ export const elasticsearchJsPlugin = (Client: any, config: any, components: any)
method: 'GET',
});

dataManagement.getDataStream = ca({
urls: [
{
fmt: '/_data_stream/<%=name%>',
req: {
name: {
type: 'string',
},
},
},
],
method: 'GET',
});

// We don't allow the user to create a data stream in the UI or API. We're just adding this here
// to enable the API integration tests.
dataManagement.createDataStream = ca({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import { RouteDependencies } from '../../../types';

import { registerGetAllRoute } from './register_get_route';
import { registerGetOneRoute, registerGetAllRoute } from './register_get_route';
import { registerDeleteRoute } from './register_delete_route';

export function registerDataStreamRoutes(dependencies: RouteDependencies) {
registerGetOneRoute(dependencies);
registerGetAllRoute(dependencies);
registerDeleteRoute(dependencies);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { deserializeDataStreamList } from '../../../../common/lib';
import { schema, TypeOf } from '@kbn/config-schema';

import { deserializeDataStream, deserializeDataStreamList } from '../../../../common/lib';
import { RouteDependencies } from '../../../types';
import { addBasePath } from '../index';

Expand Down Expand Up @@ -32,3 +34,40 @@ export function registerGetAllRoute({ router, license, lib: { isEsError } }: Rou
})
);
}

export function registerGetOneRoute({ router, license, lib: { isEsError } }: RouteDependencies) {
const paramsSchema = schema.object({
name: schema.string(),
});

router.get(
{
path: addBasePath('/data_streams/{name}'),
validate: { params: paramsSchema },
},
license.guardApiRoute(async (ctx, req, res) => {
const { name } = req.params as TypeOf<typeof paramsSchema>;
const { callAsCurrentUser } = ctx.dataManagement!.client;

try {
const dataStream = await callAsCurrentUser('dataManagement.getDataStream', { name });

if (dataStream[0]) {
const body = deserializeDataStream(dataStream[0]);
return res.ok({ body });
}

return res.notFound();
} catch (e) {
if (isEsError(e)) {
return res.customError({
statusCode: e.statusCode,
body: e,
});
}
// Case: default
return res.internalError({ body: e });
}
})
);
}

0 comments on commit f5ec8ca

Please sign in to comment.