Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a141531
Add strict payload validation to invntory_views endpoint
crespocarlos Jun 29, 2023
bf4a41c
Update README.md
crespocarlos Jun 29, 2023
6e1fe5e
Fix update endpoint payload type
crespocarlos Jun 29, 2023
d621f6b
Refactor saved view types
crespocarlos Jun 29, 2023
58b71bb
Revert some type changes and adjust toolbar_control component
crespocarlos Jun 30, 2023
f110c6e
Add strict payload validation to metrics_explorer_views endpoint
crespocarlos Jun 30, 2023
cd6f2fb
Merge branch 'main' of github.com:elastic/kibana into 157520-metric-e…
crespocarlos Jun 30, 2023
6a84cfe
Fix types
crespocarlos Jun 30, 2023
75ed125
Fix README.md
crespocarlos Jun 30, 2023
a5008a7
Metrics explorer views API type refactoring
crespocarlos Jun 30, 2023
37e2bba
Fix after changing the find_metris_explorer_view type
crespocarlos Jun 30, 2023
be063f2
Clean up
crespocarlos Jun 30, 2023
a78bddd
More clean up
crespocarlos Jun 30, 2023
de5dd7f
Fix types
crespocarlos Jun 30, 2023
8a63158
Fix test
crespocarlos Jun 30, 2023
6c59b43
Merge branch 'main' of github.com:elastic/kibana into 157520-metric-e…
crespocarlos Jul 5, 2023
8617361
Fix after merge
crespocarlos Jul 5, 2023
1dbf832
Merge branch 'main' into 157520-metric-explorer-view-strict-input-val…
kibanamachine Jul 7, 2023
bf520c2
Merge branch 'main' into 157520-metric-explorer-view-strict-input-val…
kibanamachine Jul 7, 2023
cd7c07c
Merge branch 'main' into 157520-metric-explorer-view-strict-input-val…
kibanamachine Jul 11, 2023
983d17c
Typo
crespocarlos Jul 12, 2023
b1995ba
Use proper types in metrics_explorer_views_client
crespocarlos Jul 12, 2023
dbe8b0e
typo
crespocarlos Jul 12, 2023
507696b
Adding missing files
crespocarlos Jul 12, 2023
5936cfe
Fix README.md
crespocarlos Jul 14, 2023
b5fd5b8
Merge branch 'main' into 157520-metric-explorer-view-strict-input-val…
kibanamachine Jul 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { nonEmptyStringRt } from '@kbn/io-ts-utils';
import * as rt from 'io-ts';
import { either } from 'fp-ts/Either';
import { metricsExplorerViewRT } from '../../../metrics_explorer_views';

export const METRICS_EXPLORER_VIEW_URL = '/api/infra/metrics_explorer_views';
export const METRICS_EXPLORER_VIEW_URL_ENTITY = `${METRICS_EXPLORER_VIEW_URL}/{metricsExplorerViewId}`;
Expand Down Expand Up @@ -35,28 +35,6 @@ export const metricsExplorerViewRequestQueryRT = rt.partial({

export type MetricsExplorerViewRequestQuery = rt.TypeOf<typeof metricsExplorerViewRequestQueryRT>;

const metricsExplorerViewAttributesResponseRT = rt.intersection([
rt.strict({
name: nonEmptyStringRt,
isDefault: rt.boolean,
isStatic: rt.boolean,
}),
rt.UnknownRecord,
]);

const metricsExplorerViewResponseRT = rt.exact(
rt.intersection([
rt.type({
id: rt.string,
attributes: metricsExplorerViewAttributesResponseRT,
}),
rt.partial({
updatedAt: rt.number,
version: rt.string,
}),
])
);

export const metricsExplorerViewResponsePayloadRT = rt.type({
data: metricsExplorerViewResponseRT,
data: metricsExplorerViewRT,
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* 2.0.
*/

import { nonEmptyStringRt } from '@kbn/io-ts-utils';
import * as rt from 'io-ts';
import {
metricsExplorerViewAttributesRT,
metricsExplorerViewRT,
} from '../../../metrics_explorer_views';

export const createMetricsExplorerViewAttributesRequestPayloadRT = rt.intersection([
rt.type({
name: nonEmptyStringRt,
}),
rt.UnknownRecord,
rt.exact(rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined })),
metricsExplorerViewAttributesRT,
rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined }),
]);

export type CreateMetricsExplorerViewAttributesRequestPayload = rt.TypeOf<
Expand All @@ -23,3 +23,5 @@ export type CreateMetricsExplorerViewAttributesRequestPayload = rt.TypeOf<
export const createMetricsExplorerViewRequestPayloadRT = rt.type({
attributes: createMetricsExplorerViewAttributesRequestPayloadRT,
});

export type CreateMetricsExplorerViewResponsePayload = rt.TypeOf<typeof metricsExplorerViewRT>;
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,13 @@
* 2.0.
*/

import { nonEmptyStringRt } from '@kbn/io-ts-utils';
import * as rt from 'io-ts';

export const findMetricsExplorerViewAttributesResponseRT = rt.strict({
name: nonEmptyStringRt,
isDefault: rt.boolean,
isStatic: rt.boolean,
});

const findMetricsExplorerViewResponseRT = rt.exact(
rt.intersection([
rt.type({
id: rt.string,
attributes: findMetricsExplorerViewAttributesResponseRT,
}),
rt.partial({
updatedAt: rt.number,
version: rt.string,
}),
])
);
import { singleMetricsExplorerViewRT } from '../../../metrics_explorer_views';

export const findMetricsExplorerViewResponsePayloadRT = rt.type({
data: rt.array(findMetricsExplorerViewResponseRT),
data: rt.array(singleMetricsExplorerViewRT),
});

export type FindMetricsExplorerViewResponsePayload = rt.TypeOf<
typeof findMetricsExplorerViewResponsePayloadRT
>;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
*/

import * as rt from 'io-ts';
import { metricsExplorerViewRT } from '../../../metrics_explorer_views';

export const getMetricsExplorerViewRequestParamsRT = rt.type({
metricsExplorerViewId: rt.string,
});

export type GetMetricsExplorerViewResponsePayload = rt.TypeOf<typeof metricsExplorerViewRT>;
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* 2.0.
*/

import { nonEmptyStringRt } from '@kbn/io-ts-utils';
import * as rt from 'io-ts';
import {
metricsExplorerViewAttributesRT,
metricsExplorerViewRT,
} from '../../../metrics_explorer_views';

export const updateMetricsExplorerViewAttributesRequestPayloadRT = rt.intersection([
rt.type({
name: nonEmptyStringRt,
}),
rt.UnknownRecord,
rt.exact(rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined })),
metricsExplorerViewAttributesRT,
rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined }),
]);

export type UpdateMetricsExplorerViewAttributesRequestPayload = rt.TypeOf<
Expand All @@ -23,3 +23,5 @@ export type UpdateMetricsExplorerViewAttributesRequestPayload = rt.TypeOf<
export const updateMetricsExplorerViewRequestPayloadRT = rt.type({
attributes: updateMetricsExplorerViewAttributesRequestPayloadRT,
});

export type UpdateMetricsExplorerViewResponsePayload = rt.TypeOf<typeof metricsExplorerViewRT>;
17 changes: 11 additions & 6 deletions x-pack/plugins/infra/common/metrics_explorer_views/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

import { i18n } from '@kbn/i18n';
import type { NonEmptyString } from '@kbn/io-ts-utils';
import type { MetricsExplorerViewAttributes } from './types';
import { Color } from '../color_palette';
import {
MetricsExplorerChartType,
MetricsExplorerViewAttributes,
MetricsExplorerYAxisMode,
} from './types';

export const staticMetricsExplorerViewId = '0';

Expand All @@ -23,24 +28,24 @@ export const staticMetricsExplorerViewAttributes: MetricsExplorerViewAttributes
{
aggregation: 'avg',
field: 'system.cpu.total.norm.pct',
color: 'color0',
color: Color.color0,
},
{
aggregation: 'avg',
field: 'kubernetes.pod.cpu.usage.node.pct',
color: 'color1',
color: Color.color1,
},
{
aggregation: 'avg',
field: 'docker.cpu.total.pct',
color: 'color2',
color: Color.color2,
},
],
source: 'default',
},
chartOptions: {
type: 'line',
yAxisMode: 'fromZero',
type: MetricsExplorerChartType.line,
yAxisMode: MetricsExplorerYAxisMode.fromZero,
stack: false,
},
currentTimerange: {
Expand Down
119 changes: 110 additions & 9 deletions x-pack/plugins/infra/common/metrics_explorer_views/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,101 @@
* 2.0.
*/

import { nonEmptyStringRt } from '@kbn/io-ts-utils';
import { isoToEpochRt, nonEmptyStringRt } from '@kbn/io-ts-utils';
import * as rt from 'io-ts';
import { Color } from '../color_palette';
import {
metricsExplorerAggregationRT,
metricsExplorerMetricRT,
} from '../http_api/metrics_explorer';

export const metricsExplorerViewAttributesRT = rt.intersection([
rt.type({
name: nonEmptyStringRt,
isDefault: rt.boolean,
isStatic: rt.boolean,
export const inventorySortOptionRT = rt.type({
by: rt.keyof({ name: null, value: null }),
direction: rt.keyof({ asc: null, desc: null }),
});

export enum MetricsExplorerChartType {
line = 'line',
area = 'area',
bar = 'bar',
}

export enum MetricsExplorerYAxisMode {
fromZero = 'fromZero',
auto = 'auto',
}

export const metricsExplorerChartOptionsRT = rt.type({
yAxisMode: rt.keyof(
Object.fromEntries(Object.values(MetricsExplorerYAxisMode).map((v) => [v, null])) as Record<
MetricsExplorerYAxisMode,
null
>
),
type: rt.keyof(
Object.fromEntries(Object.values(MetricsExplorerChartType).map((v) => [v, null])) as Record<
MetricsExplorerChartType,
null
>
),
stack: rt.boolean,
});

export const metricsExplorerTimeOptionsRT = rt.type({
from: rt.string,
to: rt.string,
interval: rt.string,
});
const metricsExplorerOptionsMetricRT = rt.intersection([
metricsExplorerMetricRT,
rt.partial({
rate: rt.boolean,
color: rt.keyof(
Object.fromEntries(Object.values(Color).map((c) => [c, null])) as Record<Color, null>
),
label: rt.string,
}),
rt.UnknownRecord,
]);

export type MetricsExplorerViewAttributes = rt.TypeOf<typeof metricsExplorerViewAttributesRT>;
export const metricExplorerOptionsRequiredRT = rt.type({
aggregation: metricsExplorerAggregationRT,
metrics: rt.array(metricsExplorerOptionsMetricRT),
});

export const metricExplorerOptionsOptionalRT = rt.partial({
limit: rt.number,
groupBy: rt.union([rt.string, rt.array(rt.string)]),
filterQuery: rt.string,
source: rt.string,
forceInterval: rt.boolean,
dropLastBucket: rt.boolean,
});
export const metricsExplorerOptionsRT = rt.intersection([
metricExplorerOptionsRequiredRT,
metricExplorerOptionsOptionalRT,
]);

export const metricExplorerViewStateRT = rt.type({
chartOptions: metricsExplorerChartOptionsRT,
currentTimerange: metricsExplorerTimeOptionsRT,
options: metricsExplorerOptionsRT,
});

export const metricsExplorerViewBasicAttributesRT = rt.type({
name: nonEmptyStringRt,
});

const metricsExplorerViewFlagsRT = rt.partial({ isDefault: rt.boolean, isStatic: rt.boolean });

export const metricsExplorerViewAttributesRT = rt.intersection([
metricExplorerViewStateRT,
metricsExplorerViewBasicAttributesRT,
metricsExplorerViewFlagsRT,
]);

const singleMetricsExplorerViewAttributesRT = rt.exact(
rt.intersection([metricsExplorerViewBasicAttributesRT, metricsExplorerViewFlagsRT])
);

export const metricsExplorerViewRT = rt.exact(
rt.intersection([
Expand All @@ -26,10 +108,29 @@ export const metricsExplorerViewRT = rt.exact(
attributes: metricsExplorerViewAttributesRT,
}),
rt.partial({
updatedAt: rt.number,
updatedAt: isoToEpochRt,
version: rt.string,
}),
])
);

export const singleMetricsExplorerViewRT = rt.exact(
rt.intersection([
rt.type({
id: rt.string,
attributes: singleMetricsExplorerViewAttributesRT,
}),
rt.partial({
updatedAt: isoToEpochRt,
version: rt.string,
}),
])
);

export type MetricsExplorerChartOptions = rt.TypeOf<typeof metricsExplorerChartOptionsRT>;
export type MetricsExplorerOptions = rt.TypeOf<typeof metricsExplorerOptionsRT>;
export type MetricsExplorerOptionsMetric = rt.TypeOf<typeof metricsExplorerOptionsMetricRT>;
export type MetricsExplorerViewState = rt.TypeOf<typeof metricExplorerViewStateRT>;
export type MetricsExplorerTimeOptions = rt.TypeOf<typeof metricsExplorerTimeOptionsRT>;
export type MetricsExplorerViewAttributes = rt.TypeOf<typeof metricsExplorerViewAttributesRT>;
export type MetricsExplorerView = rt.TypeOf<typeof metricsExplorerViewRT>;
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { MetricsSourceConfiguration } from '../../../../common/metrics_sources';
import { MetricExpression, TimeRange } from '../types';
import {
MetricsExplorerOptions,
MetricsExplorerTimestampsRT,
MetricsExplorerTimestamp,
} from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options';
import { useMetricsExplorerData } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data';
import { MetricExplorerCustomMetricAggregations } from '../../../../common/http_api/metrics_explorer';
Expand Down Expand Up @@ -59,7 +59,7 @@ export const useMetricsExplorerChartData = (
groupBy,
]
);
const timestamps: MetricsExplorerTimestampsRT = useMemo(() => {
const timestamps: MetricsExplorerTimestamp = useMemo(() => {
const from = timeRange.from ?? `now-${(timeSize || 1) * 20}${timeUnit}`;
const to = timeRange.to ?? 'now';
const fromTimestamp = DateMath.parse(from)!.valueOf();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import React, { useMemo } from 'react';
import { ThrowReporter } from 'io-ts/lib/ThrowReporter';
import { UrlStateContainer } from '../../utils/url_state';
import {
MetricsExplorerOptions,
type MetricsExplorerOptions,
type MetricsExplorerTimeOptions,
type MetricsExplorerChartOptions,
useMetricsExplorerOptionsContainerContext,
MetricsExplorerTimeOptions,
MetricsExplorerChartOptions,
metricExplorerOptionsRT,
metricsExplorerOptionsRT,
metricsExplorerChartOptionsRT,
metricsExplorerTimeOptionsRT,
} from '../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options';
Expand Down Expand Up @@ -73,7 +73,7 @@ export const WithMetricsExplorerOptionsUrlState = () => {
};

function isMetricExplorerOptions(subject: any): subject is MetricsExplorerOptions {
const result = metricExplorerOptionsRT.decode(subject);
const result = metricsExplorerOptionsRT.decode(subject);

try {
ThrowReporter.report(result);
Expand Down
7 changes: 5 additions & 2 deletions x-pack/plugins/infra/public/hooks/use_inventory_views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import {
UpdateViewParams,
} from '../../common/saved_views';
import { MetricsSourceConfigurationResponse } from '../../common/metrics_sources';
import { CreateInventoryViewAttributesRequestPayload } from '../../common/http_api/latest';
import {
CreateInventoryViewAttributesRequestPayload,
UpdateInventoryViewAttributesRequestPayload,
} from '../../common/http_api/latest';
import type { InventoryView } from '../../common/inventory_views';
import { useKibanaContextForPlugin } from './use_kibana';
import { useUrlState } from '../utils/use_url_state';
Expand Down Expand Up @@ -133,7 +136,7 @@ export const useInventoryViews = (): UseInventoryViewsResult => {
const { mutateAsync: updateViewById, isLoading: isUpdatingView } = useMutation<
InventoryView,
ServerError,
UpdateViewParams<CreateInventoryViewAttributesRequestPayload>
UpdateViewParams<UpdateInventoryViewAttributesRequestPayload>
>({
mutationFn: ({ id, attributes }) => inventoryViews.client.updateInventoryView(id, attributes),
onError: (error) => {
Expand Down
Loading