mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Uptime] Remove monitor states graphql (#62853)
* WIP replacing GQL with redux/rest. * Finish implementing migration. * Introduce new connected component for ping list. * Replace GraphQL type with io-ts. * Update some broken tests. * Add test for new helper function. * Write test snapshots. * Migrate api tests from graphql to rest. * Update fixtures that rely on pings. * Move ping types to runtime_types folder with rest of io-ts files. * Update Ping type location and imports, type checking. * Remove reliance on fixtures for ping functional API tests. * Fix broken unit tests. * Fix broken types. * Remove local state storage from parent components. * Add functional test to cover Ping List functionality. * Fix monitor page functional test that was broken by merge conflicts. * Fix broken tests. * Fix broken API test. * Replace a test with a describe block that will pre-navigate all tests. * Delete unused reducer keys. * Re-introduce loading to ping list reducer. * Inroduce code that will cause PingList to re-fetch when refresh button is pressed. * Update expanded rows to support multiple concurrent expanded rows. * Modify pingList reducer to have singular optional error field. * Delete unnecessary helper code. * Delete unused interface. * Add runtime_type to parse getPings params, fix pagination index. * Add dedicated monitor type to runtime_types. * Fix broken tests. * Fix broken tests. * Rename '@timestamp' property to 'timestamp' on Ping type. * Fix broken type and key pings list table on document ID instead of timestamp. * Fix broken unit tests. * Fix broken tests and types. * Fix broken functional test. * Add REST endpoint for monitor states. * Add REST route to constants file. * Introduce io-ts typing for monitor states. * Remove remaining GraphQL types. * Update monitor states types to use io-ts types. * Add state management for monitor states. * Introduce connected monitor list component. * Fixup runtime types for monitor states. * Remove all remaining references to apollo graphql. * Update URL generator function tests to use inline snapshots instead of snapshot files. * Fix missing imports and small type issues. * Prefer inline snapshot to object literal comparison. * Add type check and console log to API response. * Update README to remove graphql references. * Fix type error. * Make monitor list refresh when global refresh button is pressed. * Fix broken types. * Rename `@timestamp` field to `timestamp`. * Change spelling of var. * Add timestamp map for `@timestamp` field in monitor states fetcher. * Remove need for `monito_states` fixture. * Write test code that allows for deletion of the `monitor_states_id_filtered` fixture. * Rewrite pagination tests to no longer rely on monitor states page fixtures. * Skip test that is causing other functional tests to fail. * Remove unused translations. * Fix broken test snapshots. * Fix stale error reporting errors. * Remove runtime validation from REST handler. Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c4ddd00540
commit
7efe7e88d3
146 changed files with 2269 additions and 35220 deletions
|
@ -3,7 +3,7 @@
|
|||
## Purpose
|
||||
|
||||
The purpose of this plugin is to provide users of Heartbeat more visibility of what's happening
|
||||
in their infrastructure. It's primarily built using React and Apollo's GraphQL tools.
|
||||
in their infrastructure.
|
||||
|
||||
## Layout
|
||||
|
||||
|
@ -11,13 +11,15 @@ There are three sections to the app, `common`, `public`, and `server`.
|
|||
|
||||
### common
|
||||
|
||||
Contains GraphQL types, constants and a few other files.
|
||||
Contains runtime types types, constants and a few other files.
|
||||
|
||||
Notably, we use `io-ts`/`fp-ts` functions and types to help provide
|
||||
additional runtime safety for our API requests/responses.
|
||||
|
||||
### public
|
||||
|
||||
Components come in two main types, queries and functional. Queries are extended from Apollo's queries
|
||||
type which abstracts a lot of the GraphQL connectivity away. Functional are dumb components that
|
||||
don't store any state.
|
||||
We use Redux and associated tools for managing our app state. Components come in the usual `connect`ed and
|
||||
presentational varieties.
|
||||
|
||||
The `lib` directory controls bootstrapping code and adapter types.
|
||||
|
||||
|
@ -27,12 +29,13 @@ The principal structure of the app is stored in `uptime_app.tsx`.
|
|||
|
||||
### server
|
||||
|
||||
There is a `graphql` directory which contains the resolvers, schema files, and constants.
|
||||
|
||||
The `lib` directory contains `adapters`, which are connections to external resources like Kibana
|
||||
Server, Elasticsearch, etc. In addition, it contains domains, which are libraries that provide
|
||||
functionality via adapters.
|
||||
|
||||
The `requests` directory contains functions responsible for querying Elasticsearch and parsing its
|
||||
responses.
|
||||
|
||||
There's also a `rest_api` folder that defines the structure of the RESTful API endpoints.
|
||||
|
||||
## Testing
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SortOrder, CursorDirection } from '../graphql/types';
|
||||
import { CursorDirection, SortOrder } from '../runtime_types';
|
||||
|
||||
/**
|
||||
* The Uptime UI utilizes a settings context, the defaults for which are stored here.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
export enum API_URLS {
|
||||
INDEX_PATTERN = `/api/uptime/index_pattern`,
|
||||
INDEX_STATUS = '/api/uptime/index_status',
|
||||
MONITOR_LIST = `/api/uptime/monitor/list`,
|
||||
MONITOR_LOCATIONS = `/api/uptime/monitor/locations`,
|
||||
MONITOR_DURATION = `/api/uptime/monitor/duration`,
|
||||
MONITOR_DETAILS = `/api/uptime/monitor/details`,
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
/* tslint:disable */
|
||||
|
||||
// ====================================================
|
||||
// START: Typescript template
|
||||
// ====================================================
|
||||
|
||||
// ====================================================
|
||||
// Scalars
|
||||
// ====================================================
|
||||
|
||||
export type UnsignedInteger = any;
|
||||
|
||||
// ====================================================
|
||||
// Types
|
||||
// ====================================================
|
||||
|
||||
export interface Query {
|
||||
/** Fetches the current state of Uptime monitors for the given parameters. */
|
||||
getMonitorStates?: MonitorSummaryResult | null;
|
||||
}
|
||||
|
||||
/** The monitor's status for a ping */
|
||||
export interface Duration {
|
||||
us?: UnsignedInteger | null;
|
||||
}
|
||||
|
||||
export interface Rtt {
|
||||
connect?: Duration | null;
|
||||
|
||||
handshake?: Duration | null;
|
||||
|
||||
validate?: Duration | null;
|
||||
}
|
||||
|
||||
export interface Summary {
|
||||
up?: number | null;
|
||||
|
||||
down?: number | null;
|
||||
|
||||
geo?: CheckGeo | null;
|
||||
}
|
||||
|
||||
export interface CheckGeo {
|
||||
name?: string | null;
|
||||
|
||||
location?: Location | null;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
lat?: number | null;
|
||||
|
||||
lon?: number | null;
|
||||
}
|
||||
|
||||
export interface DocCount {
|
||||
count: UnsignedInteger;
|
||||
}
|
||||
|
||||
/** The primary object returned for monitor states. */
|
||||
export interface MonitorSummaryResult {
|
||||
/** Used to go to the next page of results */
|
||||
prevPagePagination?: string | null;
|
||||
/** Used to go to the previous page of results */
|
||||
nextPagePagination?: string | null;
|
||||
/** The objects representing the state of a series of heartbeat monitors. */
|
||||
summaries?: MonitorSummary[] | null;
|
||||
/** The number of summaries. */
|
||||
totalSummaryCount: number;
|
||||
}
|
||||
/** Represents the current state and associated data for an Uptime monitor. */
|
||||
export interface MonitorSummary {
|
||||
/** The ID assigned by the config or generated by the user. */
|
||||
monitor_id: string;
|
||||
/** The state of the monitor and its associated details. */
|
||||
state: State;
|
||||
|
||||
histogram?: SummaryHistogram | null;
|
||||
}
|
||||
/** Unifies the subsequent data for an uptime monitor. */
|
||||
export interface State {
|
||||
/** The agent processing the monitor. */
|
||||
agent?: Agent | null;
|
||||
/** There is a check object for each instance of the monitoring agent. */
|
||||
checks?: Check[] | null;
|
||||
|
||||
geo?: StateGeo | null;
|
||||
|
||||
observer?: StateObserver | null;
|
||||
|
||||
monitor?: MonitorState | null;
|
||||
|
||||
summary: Summary;
|
||||
|
||||
timestamp: UnsignedInteger;
|
||||
/** Transport encryption information. */
|
||||
tls?: (StateTls | null)[] | null;
|
||||
|
||||
url?: StateUrl | null;
|
||||
}
|
||||
|
||||
export interface Agent {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Check {
|
||||
agent?: Agent | null;
|
||||
|
||||
container?: StateContainer | null;
|
||||
|
||||
kubernetes?: StateKubernetes | null;
|
||||
|
||||
monitor: CheckMonitor;
|
||||
|
||||
observer?: CheckObserver | null;
|
||||
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface StateContainer {
|
||||
id?: string | null;
|
||||
}
|
||||
|
||||
export interface StateKubernetes {
|
||||
pod?: StatePod | null;
|
||||
}
|
||||
|
||||
export interface StatePod {
|
||||
uid?: string | null;
|
||||
}
|
||||
|
||||
export interface CheckMonitor {
|
||||
ip?: string | null;
|
||||
|
||||
name?: string | null;
|
||||
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface CheckObserver {
|
||||
geo?: CheckGeo | null;
|
||||
}
|
||||
|
||||
export interface StateGeo {
|
||||
name?: (string | null)[] | null;
|
||||
|
||||
location?: Location | null;
|
||||
}
|
||||
|
||||
export interface StateObserver {
|
||||
geo?: StateGeo | null;
|
||||
}
|
||||
|
||||
export interface MonitorState {
|
||||
status?: string | null;
|
||||
|
||||
name?: string | null;
|
||||
|
||||
id?: string | null;
|
||||
|
||||
type?: string | null;
|
||||
}
|
||||
/** Contains monitor transmission encryption information. */
|
||||
export interface StateTls {
|
||||
/** The date and time after which the certificate is invalid. */
|
||||
certificate_not_valid_after?: string | null;
|
||||
|
||||
certificate_not_valid_before?: string | null;
|
||||
|
||||
certificates?: string | null;
|
||||
|
||||
rtt?: Rtt | null;
|
||||
}
|
||||
|
||||
export interface StateUrl {
|
||||
domain?: string | null;
|
||||
|
||||
full?: string | null;
|
||||
|
||||
path?: string | null;
|
||||
|
||||
port?: number | null;
|
||||
|
||||
scheme?: string | null;
|
||||
}
|
||||
/** Monitor status data over time. */
|
||||
export interface SummaryHistogram {
|
||||
/** The number of documents used to assemble the histogram. */
|
||||
count: number;
|
||||
/** The individual histogram data points. */
|
||||
points: SummaryHistogramPoint[];
|
||||
}
|
||||
/** Represents a monitor's statuses for a period of time. */
|
||||
export interface SummaryHistogramPoint {
|
||||
/** The time at which these data were collected. */
|
||||
timestamp: UnsignedInteger;
|
||||
/** The number of _up_ documents. */
|
||||
up: number;
|
||||
/** The number of _down_ documents. */
|
||||
down: number;
|
||||
}
|
||||
|
||||
export interface GetMonitorStatesQueryArgs {
|
||||
dateRangeStart: string;
|
||||
|
||||
dateRangeEnd: string;
|
||||
|
||||
pagination?: string | null;
|
||||
|
||||
filters?: string | null;
|
||||
|
||||
statusFilter?: string | null;
|
||||
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Enums
|
||||
// ====================================================
|
||||
|
||||
export enum CursorDirection {
|
||||
AFTER = 'AFTER',
|
||||
BEFORE = 'BEFORE',
|
||||
}
|
||||
|
||||
export enum SortOrder {
|
||||
ASC = 'ASC',
|
||||
DESC = 'DESC',
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// END: Typescript template
|
||||
// ====================================================
|
|
@ -6,3 +6,4 @@
|
|||
|
||||
export * from './details';
|
||||
export * from './locations';
|
||||
export * from './state';
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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 t from 'io-ts';
|
||||
|
||||
export const CheckMonitorType = t.intersection([
|
||||
t.partial({
|
||||
name: t.string,
|
||||
ip: t.union([t.array(t.string), t.string]),
|
||||
}),
|
||||
t.type({
|
||||
status: t.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CheckType = t.intersection([
|
||||
t.partial({
|
||||
agent: t.partial({
|
||||
id: t.string,
|
||||
}),
|
||||
container: t.type({
|
||||
id: t.string,
|
||||
}),
|
||||
kubernetes: t.type({
|
||||
pod: t.type({
|
||||
uid: t.string,
|
||||
}),
|
||||
}),
|
||||
observer: t.type({
|
||||
geo: t.partial({
|
||||
name: t.string,
|
||||
location: t.partial({
|
||||
lat: t.number,
|
||||
lon: t.number,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
t.type({
|
||||
monitor: CheckMonitorType,
|
||||
timestamp: t.number,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type Check = t.TypeOf<typeof CheckType>;
|
||||
|
||||
export const StateType = t.intersection([
|
||||
t.partial({
|
||||
checks: t.array(CheckType),
|
||||
observer: t.partial({
|
||||
geo: t.partial({
|
||||
name: t.array(t.string),
|
||||
}),
|
||||
}),
|
||||
summary: t.partial({
|
||||
up: t.number,
|
||||
down: t.number,
|
||||
geo: t.partial({
|
||||
name: t.string,
|
||||
location: t.partial({
|
||||
lat: t.number,
|
||||
lon: t.number,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
t.type({
|
||||
timestamp: t.string,
|
||||
url: t.partial({
|
||||
domain: t.string,
|
||||
full: t.string,
|
||||
path: t.string,
|
||||
port: t.number,
|
||||
scheme: t.string,
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const HistogramPointType = t.type({
|
||||
timestamp: t.number,
|
||||
up: t.number,
|
||||
down: t.number,
|
||||
});
|
||||
|
||||
export type HistogramPoint = t.TypeOf<typeof HistogramPointType>;
|
||||
|
||||
export const HistogramType = t.type({
|
||||
count: t.number,
|
||||
points: t.array(HistogramPointType),
|
||||
});
|
||||
|
||||
export type Histogram = t.TypeOf<typeof HistogramType>;
|
||||
|
||||
export const MonitorSummaryType = t.intersection([
|
||||
t.type({
|
||||
monitor_id: t.string,
|
||||
state: StateType,
|
||||
}),
|
||||
t.partial({
|
||||
histogram: HistogramType,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type MonitorSummary = t.TypeOf<typeof MonitorSummaryType>;
|
||||
|
||||
export const MonitorSummaryResultType = t.intersection([
|
||||
t.partial({
|
||||
summaries: t.array(MonitorSummaryType),
|
||||
}),
|
||||
t.type({
|
||||
prevPagePagination: t.union([t.string, t.null]),
|
||||
nextPagePagination: t.union([t.string, t.null]),
|
||||
totalSummaryCount: t.number,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type MonitorSummaryResult = t.TypeOf<typeof MonitorSummaryResultType>;
|
||||
|
||||
export const FetchMonitorStatesQueryArgsType = t.intersection([
|
||||
t.partial({
|
||||
pagination: t.string,
|
||||
filters: t.string,
|
||||
statusFilter: t.string,
|
||||
}),
|
||||
t.type({
|
||||
dateRangeStart: t.string,
|
||||
dateRangeEnd: t.string,
|
||||
pageSize: t.number,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type FetchMonitorStatesQueryArgs = t.TypeOf<typeof FetchMonitorStatesQueryArgsType>;
|
||||
|
||||
export enum CursorDirection {
|
||||
AFTER = 'AFTER',
|
||||
BEFORE = 'BEFORE',
|
||||
}
|
||||
|
||||
export enum SortOrder {
|
||||
ASC = 'ASC',
|
||||
DESC = 'DESC',
|
||||
}
|
|
@ -11,6 +11,7 @@ export { KueryBar } from './kuerybar/kuery_bar_container';
|
|||
export { FilterGroup } from './filter_group/filter_group_container';
|
||||
export { MonitorStatusDetails } from './monitor/status_details_container';
|
||||
export { MonitorStatusBar } from './monitor/status_bar_container';
|
||||
export { MonitorList } from './monitor/monitor_list';
|
||||
export { MonitorListDrawer } from './monitor/list_drawer_container';
|
||||
export { MonitorListActionsPopover } from './monitor/drawer_popover_container';
|
||||
export { PingList, PingListProps } from './pings';
|
||||
|
|
|
@ -12,8 +12,7 @@ import { MonitorDetailsActionPayload } from '../../../state/actions/types';
|
|||
import { getMonitorDetailsAction } from '../../../state/actions/monitor';
|
||||
import { MonitorListDrawerComponent } from '../../functional/monitor_list/monitor_list_drawer/monitor_list_drawer';
|
||||
import { useGetUrlParams } from '../../../hooks';
|
||||
import { MonitorSummary } from '../../../../common/graphql/types';
|
||||
import { MonitorDetails } from '../../../../common/runtime_types/monitor';
|
||||
import { MonitorDetails, MonitorSummary } from '../../../../common/runtime_types';
|
||||
|
||||
interface ContainerProps {
|
||||
summary: MonitorSummary;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 React, { useCallback } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { getMonitorList } from '../../../state/actions';
|
||||
import { FetchMonitorStatesQueryArgs } from '../../../../common/runtime_types';
|
||||
import { monitorListSelector } from '../../../state/selectors';
|
||||
import { MonitorListComponent } from '../../functional/monitor_list';
|
||||
|
||||
export interface MonitorListProps {
|
||||
filters?: string;
|
||||
linkParameters?: string;
|
||||
}
|
||||
|
||||
export const MonitorList: React.FC<MonitorListProps> = props => {
|
||||
const dispatch = useDispatch();
|
||||
const dispatchCallback = useCallback(
|
||||
(params: FetchMonitorStatesQueryArgs) => {
|
||||
dispatch(getMonitorList(params));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
const monitorListState = useSelector(monitorListSelector);
|
||||
return (
|
||||
<MonitorListComponent {...props} {...monitorListState} getMonitorList={dispatchCallback} />
|
||||
);
|
||||
};
|
|
@ -82,7 +82,6 @@ exports[`MonitorBarSeries component shallow renders a series when there are down
|
|||
}
|
||||
>
|
||||
<MonitorBarSeries
|
||||
dangerColor="A danger color"
|
||||
histogramSeries={
|
||||
Array [
|
||||
Object {
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
import React from 'react';
|
||||
import { MonitorBarSeries, MonitorBarSeriesProps } from '../monitor_bar_series';
|
||||
import { renderWithRouter, shallowWithRouter } from '../../../../lib';
|
||||
import { SummaryHistogramPoint } from '../../../../../common/graphql/types';
|
||||
import { HistogramPoint } from '../../../../../common/runtime_types';
|
||||
|
||||
describe('MonitorBarSeries component', () => {
|
||||
let props: MonitorBarSeriesProps;
|
||||
let histogramSeries: SummaryHistogramPoint[];
|
||||
let histogramSeries: HistogramPoint[];
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
dangerColor: 'A danger color',
|
||||
histogramSeries: [
|
||||
{
|
||||
timestamp: 124,
|
||||
|
@ -193,16 +192,12 @@ describe('MonitorBarSeries component', () => {
|
|||
});
|
||||
|
||||
it('shallow renders nothing if the data series is null', () => {
|
||||
const component = shallowWithRouter(
|
||||
<MonitorBarSeries dangerColor="danger" histogramSeries={null} />
|
||||
);
|
||||
const component = shallowWithRouter(<MonitorBarSeries histogramSeries={null} />);
|
||||
expect(component).toEqual({});
|
||||
});
|
||||
|
||||
it('renders if the data series is present', () => {
|
||||
const component = renderWithRouter(
|
||||
<MonitorBarSeries dangerColor="danger" histogramSeries={histogramSeries} />
|
||||
);
|
||||
const component = renderWithRouter(<MonitorBarSeries histogramSeries={histogramSeries} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,23 +14,20 @@ import {
|
|||
timeFormatter,
|
||||
} from '@elastic/charts';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import moment from 'moment';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiText, EuiToolTip } from '@elastic/eui';
|
||||
import { SummaryHistogramPoint } from '../../../../common/graphql/types';
|
||||
import { HistogramPoint } from '../../../../common/runtime_types';
|
||||
import { getChartDateLabel, seriesHasDownValues } from '../../../lib/helper';
|
||||
import { useUrlParams } from '../../../hooks';
|
||||
import { UptimeThemeContext } from '../../../contexts';
|
||||
|
||||
export interface MonitorBarSeriesProps {
|
||||
/**
|
||||
* The color to use for the display of down states.
|
||||
*/
|
||||
dangerColor: string;
|
||||
/**
|
||||
* The timeseries data to display.
|
||||
*/
|
||||
histogramSeries: SummaryHistogramPoint[] | null;
|
||||
histogramSeries: HistogramPoint[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,7 +35,10 @@ export interface MonitorBarSeriesProps {
|
|||
* so we will only render the series component if there are down counts for the selected monitor.
|
||||
* @param props - the values for the monitor this chart visualizes
|
||||
*/
|
||||
export const MonitorBarSeries = ({ dangerColor, histogramSeries }: MonitorBarSeriesProps) => {
|
||||
export const MonitorBarSeries = ({ histogramSeries }: MonitorBarSeriesProps) => {
|
||||
const {
|
||||
colors: { danger },
|
||||
} = useContext(UptimeThemeContext);
|
||||
const [getUrlParams, updateUrlParams] = useUrlParams();
|
||||
const { absoluteDateRangeStart, absoluteDateRangeEnd } = getUrlParams();
|
||||
|
||||
|
@ -68,7 +68,7 @@ export const MonitorBarSeries = ({ dangerColor, histogramSeries }: MonitorBarSer
|
|||
/>
|
||||
<BarSeries
|
||||
id={id}
|
||||
color={dangerColor}
|
||||
color={danger}
|
||||
data={(histogramSeries || []).map(({ timestamp, down }) => [timestamp, down])}
|
||||
name={i18n.translate('xpack.uptime.monitorList.downLineSeries.downLabel', {
|
||||
defaultMessage: 'Down checks',
|
||||
|
|
|
@ -13,7 +13,7 @@ export * from './alerts';
|
|||
export { DonutChart } from './charts/donut_chart';
|
||||
export { KueryBarComponent } from './kuery_bar/kuery_bar';
|
||||
export { MonitorCharts } from './monitor_charts';
|
||||
export { MonitorList } from './monitor_list';
|
||||
export { MonitorListComponent } from './monitor_list';
|
||||
export { OverviewPageParsingErrorCallout } from './overview_page_parsing_error_callout';
|
||||
export { PingListComponent } from './ping_list';
|
||||
export { PingHistogramComponent } from './charts';
|
||||
|
|
|
@ -1,125 +1,535 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`MonitorList component renders a no items message when no data is provided 1`] = `
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Monitor status"
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiBasicTable
|
||||
aria-label="Monitor Status table with columns for Status, Name, URL, IP, Downtime History and Integrations. The table is currently displaying 0 items."
|
||||
columns={
|
||||
Array [
|
||||
exports[`MonitorList component MonitorListPagination component renders a no items message when no data is provided 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.status",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Status",
|
||||
"render": [Function],
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.name",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Name",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.url.full",
|
||||
"name": "Url",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "center",
|
||||
"field": "histogram.points",
|
||||
"mobileOptions": Object {
|
||||
"show": false,
|
||||
},
|
||||
"name": "Downtime history",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "right",
|
||||
"field": "monitor_id",
|
||||
"isExpander": true,
|
||||
"name": "",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
"width": "24px",
|
||||
},
|
||||
]
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"list": Object {
|
||||
"nextPagePagination": null,
|
||||
"prevPagePagination": null,
|
||||
"summaries": Array [],
|
||||
"totalSummaryCount": 0,
|
||||
},
|
||||
"loading": false,
|
||||
}
|
||||
hasActions={true}
|
||||
isExpandable={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={Object {}}
|
||||
items={Array []}
|
||||
loading={false}
|
||||
noItemsMessage="No uptime monitors found"
|
||||
responsive={true}
|
||||
tableLayout="fixed"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<MonitorListPageSizeSelect
|
||||
setSize={[MockFunction]}
|
||||
size={25}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
||||
exports[`MonitorList component MonitorListPagination component renders the pagination 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"list": Object {
|
||||
"nextPagePagination": "{\\"cursorKey\\":{\\"monitor_id\\":456},\\"cursorDirection\\":\\"AFTER\\",\\"sortOrder\\":\\"ASC\\"}",
|
||||
"prevPagePagination": "{\\"cursorKey\\":{\\"monitor_id\\":123},\\"cursorDirection\\":\\"BEFORE\\",\\"sortOrder\\":\\"ASC\\"}",
|
||||
"summaries": Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 124,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
},
|
||||
"timestamp": "123",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
},
|
||||
"timestamp": "125",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
],
|
||||
"totalSummaryCount": 2,
|
||||
},
|
||||
"loading": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
||||
exports[`MonitorList component renders a no items message when no data is provided 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"list": Object {
|
||||
"nextPagePagination": null,
|
||||
"prevPagePagination": null,
|
||||
"summaries": Array [],
|
||||
"totalSummaryCount": 0,
|
||||
},
|
||||
"loading": true,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
||||
exports[`MonitorList component renders error list 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"error": [Error: foo message],
|
||||
"list": Object {
|
||||
"nextPagePagination": null,
|
||||
"prevPagePagination": null,
|
||||
"summaries": Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 124,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
},
|
||||
"timestamp": "123",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
},
|
||||
"timestamp": "125",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
],
|
||||
"totalSummaryCount": 2,
|
||||
},
|
||||
"loading": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
||||
exports[`MonitorList component renders loading state 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"list": Object {
|
||||
"nextPagePagination": null,
|
||||
"prevPagePagination": null,
|
||||
"summaries": Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 124,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
},
|
||||
"timestamp": "123",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
},
|
||||
"timestamp": "125",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
],
|
||||
"totalSummaryCount": 2,
|
||||
},
|
||||
"loading": true,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
||||
exports[`MonitorList component renders the monitor list 1`] = `
|
||||
|
@ -672,185 +1082,132 @@ exports[`MonitorList component renders the monitor list 1`] = `
|
|||
`;
|
||||
|
||||
exports[`MonitorList component shallow renders the monitor list 1`] = `
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Monitor status"
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiBasicTable
|
||||
aria-label="Monitor Status table with columns for Status, Name, URL, IP, Downtime History and Integrations. The table is currently displaying 2 items."
|
||||
columns={
|
||||
Array [
|
||||
<ContextProvider
|
||||
value={
|
||||
Object {
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"canGo": [Function],
|
||||
"createHref": [Function],
|
||||
"entries": Array [
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.status",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Status",
|
||||
"render": [Function],
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.name",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Name",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.url.full",
|
||||
"name": "Url",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "center",
|
||||
"field": "histogram.points",
|
||||
"mobileOptions": Object {
|
||||
"show": false,
|
||||
},
|
||||
"name": "Downtime history",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "right",
|
||||
"field": "monitor_id",
|
||||
"isExpander": true,
|
||||
"name": "",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
"width": "24px",
|
||||
},
|
||||
]
|
||||
}
|
||||
hasActions={true}
|
||||
isExpandable={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={Object {}}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"index": 0,
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"key": "TestKeyForTesting",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"match": Object {
|
||||
"isExact": true,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
},
|
||||
"staticContext": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<MonitorListComponent
|
||||
getMonitorList={[MockFunction]}
|
||||
lastRefresh={123}
|
||||
monitorList={
|
||||
Object {
|
||||
"list": Object {
|
||||
"nextPagePagination": null,
|
||||
"prevPagePagination": null,
|
||||
"summaries": Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 124,
|
||||
},
|
||||
"timestamp": "124",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
"timestamp": "126",
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
"timestamp": "123",
|
||||
"url": Object {},
|
||||
},
|
||||
"timestamp": "123",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 125,
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": 126,
|
||||
},
|
||||
"timestamp": "126",
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
"timestamp": "125",
|
||||
"url": Object {},
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
},
|
||||
]
|
||||
],
|
||||
"totalSummaryCount": 2,
|
||||
},
|
||||
"loading": false,
|
||||
}
|
||||
loading={false}
|
||||
noItemsMessage="No uptime monitors found"
|
||||
responsive={true}
|
||||
tableLayout="fixed"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<MonitorListPageSizeSelect
|
||||
setSize={[MockFunction]}
|
||||
size={25}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</ContextProvider>
|
||||
`;
|
||||
|
|
|
@ -1,307 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`MonitorListPagination component renders a no items message when no data is provided 1`] = `
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Monitor status"
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiBasicTable
|
||||
aria-label="Monitor Status table with columns for Status, Name, URL, IP, Downtime History and Integrations. The table is currently displaying 0 items."
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.status",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Status",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.name",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Name",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.url.full",
|
||||
"name": "Url",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "center",
|
||||
"field": "histogram.points",
|
||||
"mobileOptions": Object {
|
||||
"show": false,
|
||||
},
|
||||
"name": "Downtime history",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "right",
|
||||
"field": "monitor_id",
|
||||
"isExpander": true,
|
||||
"name": "",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
"width": "24px",
|
||||
},
|
||||
]
|
||||
}
|
||||
hasActions={true}
|
||||
isExpandable={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={Object {}}
|
||||
items={Array []}
|
||||
loading={false}
|
||||
noItemsMessage="No uptime monitors found"
|
||||
responsive={true}
|
||||
tableLayout="fixed"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<MonitorListPageSizeSelect
|
||||
setSize={[MockFunction]}
|
||||
size={25}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination=""
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`MonitorListPagination component renders the monitor list 1`] = `
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Monitor status"
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiBasicTable
|
||||
aria-label="Monitor Status table with columns for Status, Name, URL, IP, Downtime History and Integrations. The table is currently displaying 2 items."
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.status",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Status",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.monitor.name",
|
||||
"mobileOptions": Object {
|
||||
"fullWidth": true,
|
||||
},
|
||||
"name": "Name",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
},
|
||||
Object {
|
||||
"align": "left",
|
||||
"field": "state.url.full",
|
||||
"name": "Url",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "center",
|
||||
"field": "histogram.points",
|
||||
"mobileOptions": Object {
|
||||
"show": false,
|
||||
},
|
||||
"name": "Downtime history",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"align": "right",
|
||||
"field": "monitor_id",
|
||||
"isExpander": true,
|
||||
"name": "",
|
||||
"render": [Function],
|
||||
"sortable": true,
|
||||
"width": "24px",
|
||||
},
|
||||
]
|
||||
}
|
||||
hasActions={true}
|
||||
isExpandable={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={Object {}}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "124",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": "126",
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 2,
|
||||
"up": 1,
|
||||
},
|
||||
"timestamp": "123",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"checks": Array [
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "126",
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 2,
|
||||
},
|
||||
"timestamp": "125",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
loading={false}
|
||||
noItemsMessage="No uptime monitors found"
|
||||
responsive={true}
|
||||
tableLayout="fixed"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<MonitorListPageSizeSelect
|
||||
setSize={[MockFunction]}
|
||||
size={25}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination="{\\"cursorKey\\":{\\"monitor_id\\":123},\\"cursorDirection\\":\\"BEFORE\\",\\"sortOrder\\":\\"ASC\\"}"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination="{\\"cursorKey\\":{\\"monitor_id\\":456},\\"cursorDirection\\":\\"AFTER\\",\\"sortOrder\\":\\"ASC\\"}"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
|
@ -4,17 +4,30 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
import { MonitorSummaryResult } from '../../../../../common/graphql/types';
|
||||
import {
|
||||
MonitorSummaryResult,
|
||||
CursorDirection,
|
||||
SortOrder,
|
||||
} from '../../../../../common/runtime_types';
|
||||
import { MonitorListComponent } from '../monitor_list';
|
||||
import { renderWithRouter } from '../../../../lib';
|
||||
import { renderWithRouter, shallowWithRouter } from '../../../../lib';
|
||||
|
||||
describe('MonitorList component', () => {
|
||||
let result: MonitorSummaryResult;
|
||||
let localStorageMock: any;
|
||||
|
||||
beforeEach(() => {
|
||||
localStorageMock = {
|
||||
getItem: jest.fn().mockImplementation(() => '25'),
|
||||
setItem: jest.fn(),
|
||||
};
|
||||
|
||||
// @ts-ignore replacing a call to localStorage we use for monitor list size
|
||||
global.localStorage = localStorageMock;
|
||||
result = {
|
||||
nextPagePagination: null,
|
||||
prevPagePagination: null,
|
||||
summaries: [
|
||||
{
|
||||
monitor_id: 'foo',
|
||||
|
@ -25,21 +38,21 @@ describe('MonitorList component', () => {
|
|||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '124',
|
||||
timestamp: 124,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: '125',
|
||||
timestamp: 125,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.3',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: '126',
|
||||
timestamp: 126,
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
|
@ -47,6 +60,7 @@ describe('MonitorList component', () => {
|
|||
down: 2,
|
||||
},
|
||||
timestamp: '123',
|
||||
url: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -58,14 +72,14 @@ describe('MonitorList component', () => {
|
|||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '125',
|
||||
timestamp: 125,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '126',
|
||||
timestamp: 126,
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
|
@ -73,6 +87,7 @@ describe('MonitorList component', () => {
|
|||
down: 0,
|
||||
},
|
||||
timestamp: '125',
|
||||
url: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -81,15 +96,11 @@ describe('MonitorList component', () => {
|
|||
});
|
||||
|
||||
it('shallow renders the monitor list', () => {
|
||||
const component = shallowWithIntl(
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
dangerColor="danger"
|
||||
data={{ monitorStates: result }}
|
||||
hasActiveFilters={false}
|
||||
loading={false}
|
||||
pageSize={25}
|
||||
setPageSize={jest.fn()}
|
||||
successColor="primary"
|
||||
monitorList={{ list: result, loading: false }}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -97,15 +108,19 @@ describe('MonitorList component', () => {
|
|||
});
|
||||
|
||||
it('renders a no items message when no data is provided', () => {
|
||||
const component = shallowWithIntl(
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
dangerColor="danger"
|
||||
data={{}}
|
||||
hasActiveFilters={false}
|
||||
loading={false}
|
||||
pageSize={25}
|
||||
setPageSize={jest.fn()}
|
||||
successColor="primary"
|
||||
monitorList={{
|
||||
list: {
|
||||
summaries: [],
|
||||
nextPagePagination: null,
|
||||
prevPagePagination: null,
|
||||
totalSummaryCount: 0,
|
||||
},
|
||||
loading: true,
|
||||
}}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -114,16 +129,156 @@ describe('MonitorList component', () => {
|
|||
it('renders the monitor list', () => {
|
||||
const component = renderWithRouter(
|
||||
<MonitorListComponent
|
||||
dangerColor="danger"
|
||||
data={{ monitorStates: result }}
|
||||
hasActiveFilters={false}
|
||||
loading={false}
|
||||
pageSize={25}
|
||||
setPageSize={jest.fn()}
|
||||
successColor="primary"
|
||||
monitorList={{ list: result, loading: false }}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders error list', () => {
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
monitorList={{ list: result, error: new Error('foo message'), loading: false }}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders loading state', () => {
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
monitorList={{ list: result, loading: true }}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('MonitorListPagination component', () => {
|
||||
let paginationResult: MonitorSummaryResult;
|
||||
|
||||
beforeEach(() => {
|
||||
paginationResult = {
|
||||
prevPagePagination: JSON.stringify({
|
||||
cursorKey: { monitor_id: 123 },
|
||||
cursorDirection: CursorDirection.BEFORE,
|
||||
sortOrder: SortOrder.ASC,
|
||||
}),
|
||||
nextPagePagination: JSON.stringify({
|
||||
cursorKey: { monitor_id: 456 },
|
||||
cursorDirection: CursorDirection.AFTER,
|
||||
sortOrder: SortOrder.ASC,
|
||||
}),
|
||||
summaries: [
|
||||
{
|
||||
monitor_id: 'foo',
|
||||
state: {
|
||||
checks: [
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: 124,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: 125,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.3',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: 126,
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
up: 1,
|
||||
down: 2,
|
||||
},
|
||||
timestamp: '123',
|
||||
url: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
monitor_id: 'bar',
|
||||
state: {
|
||||
checks: [
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: 125,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: 126,
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
up: 2,
|
||||
down: 0,
|
||||
},
|
||||
timestamp: '125',
|
||||
url: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
totalSummaryCount: 2,
|
||||
};
|
||||
});
|
||||
|
||||
it('renders the pagination', () => {
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
monitorList={{
|
||||
list: {
|
||||
...paginationResult,
|
||||
},
|
||||
loading: false,
|
||||
}}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a no items message when no data is provided', () => {
|
||||
const component = shallowWithRouter(
|
||||
<MonitorListComponent
|
||||
monitorList={{
|
||||
list: {
|
||||
summaries: [],
|
||||
nextPagePagination: null,
|
||||
prevPagePagination: null,
|
||||
totalSummaryCount: 0,
|
||||
},
|
||||
loading: false,
|
||||
}}
|
||||
lastRefresh={123}
|
||||
getMonitorList={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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 { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
import {
|
||||
CursorDirection,
|
||||
MonitorSummaryResult,
|
||||
SortOrder,
|
||||
} from '../../../../../common/graphql/types';
|
||||
import { MonitorListComponent } from '../monitor_list';
|
||||
|
||||
describe('MonitorListPagination component', () => {
|
||||
let result: MonitorSummaryResult;
|
||||
|
||||
beforeEach(() => {
|
||||
result = {
|
||||
prevPagePagination: JSON.stringify({
|
||||
cursorKey: { monitor_id: 123 },
|
||||
cursorDirection: CursorDirection.BEFORE,
|
||||
sortOrder: SortOrder.ASC,
|
||||
}),
|
||||
nextPagePagination: JSON.stringify({
|
||||
cursorKey: { monitor_id: 456 },
|
||||
cursorDirection: CursorDirection.AFTER,
|
||||
sortOrder: SortOrder.ASC,
|
||||
}),
|
||||
summaries: [
|
||||
{
|
||||
monitor_id: 'foo',
|
||||
state: {
|
||||
checks: [
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '124',
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: '125',
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.3',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: '126',
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
up: 1,
|
||||
down: 2,
|
||||
},
|
||||
timestamp: '123',
|
||||
},
|
||||
},
|
||||
{
|
||||
monitor_id: 'bar',
|
||||
state: {
|
||||
checks: [
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '125',
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '126',
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
up: 2,
|
||||
down: 0,
|
||||
},
|
||||
timestamp: '125',
|
||||
},
|
||||
},
|
||||
],
|
||||
totalSummaryCount: 2,
|
||||
};
|
||||
});
|
||||
|
||||
it('renders the monitor list', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MonitorListComponent
|
||||
dangerColor="danger"
|
||||
data={{ monitorStates: result }}
|
||||
loading={false}
|
||||
pageSize={25}
|
||||
setPageSize={jest.fn()}
|
||||
successColor="primary"
|
||||
hasActiveFilters={false}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a no items message when no data is provided', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MonitorListComponent
|
||||
dangerColor="danger"
|
||||
data={{}}
|
||||
loading={false}
|
||||
successColor="primary"
|
||||
pageSize={25}
|
||||
setPageSize={jest.fn()}
|
||||
hasActiveFilters={false}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -8,7 +8,7 @@ import React from 'react';
|
|||
import moment from 'moment';
|
||||
import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { getLocationStatus, MonitorListStatusColumn } from '../monitor_list_status_column';
|
||||
import { Check } from '../../../../../common/graphql/types';
|
||||
import { Check } from '../../../../../common/runtime_types';
|
||||
import { STATUS } from '../../../../../common/constants';
|
||||
|
||||
describe('MonitorListStatusColumn', () => {
|
||||
|
@ -29,9 +29,6 @@ describe('MonitorListStatusColumn', () => {
|
|||
beforeEach(() => {
|
||||
upChecks = [
|
||||
{
|
||||
agent: { id: '6a2f2a1c-e346-49ed-8418-6d48af8841d6' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -46,12 +43,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794631464',
|
||||
timestamp: 1579794631464,
|
||||
},
|
||||
{
|
||||
agent: { id: '1117fd01-bc1a-4aa5-bfab-40ab455eadf9' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -66,12 +60,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794634220',
|
||||
timestamp: 1579794634220,
|
||||
},
|
||||
{
|
||||
agent: { id: 'eda59510-45e8-4dfe-b0f8-959c449e3565' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -86,15 +77,12 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794628368',
|
||||
timestamp: 1579794628368,
|
||||
},
|
||||
];
|
||||
|
||||
downChecks = [
|
||||
{
|
||||
agent: { id: '6a2f2a1c-e346-49ed-8418-6d48af8841d6' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -109,12 +97,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794631464',
|
||||
timestamp: 1579794631464,
|
||||
},
|
||||
{
|
||||
agent: { id: '1117fd01-bc1a-4aa5-bfab-40ab455eadf9' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -129,12 +114,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794634220',
|
||||
timestamp: 1579794634220,
|
||||
},
|
||||
{
|
||||
agent: { id: 'eda59510-45e8-4dfe-b0f8-959c449e3565' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -149,15 +131,12 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794628368',
|
||||
timestamp: 1579794628368,
|
||||
},
|
||||
];
|
||||
|
||||
checks = [
|
||||
{
|
||||
agent: { id: '6a2f2a1c-e346-49ed-8418-6d48af8841d6' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -172,12 +151,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794631464',
|
||||
timestamp: 1579794631464,
|
||||
},
|
||||
{
|
||||
agent: { id: '1117fd01-bc1a-4aa5-bfab-40ab455eadf9' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -192,12 +168,9 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794634220',
|
||||
timestamp: 1579794634220,
|
||||
},
|
||||
{
|
||||
agent: { id: 'eda59510-45e8-4dfe-b0f8-959c449e3565' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '104.86.46.103',
|
||||
name: '',
|
||||
|
@ -212,7 +185,7 @@ describe('MonitorListStatusColumn', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
timestamp: '1579794628368',
|
||||
timestamp: 1579794628368,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { MonitorList } from './monitor_list';
|
||||
export { MonitorListComponent } from './monitor_list';
|
||||
export { Criteria, Pagination } from './types';
|
||||
export { LocationLink } from './monitor_list_drawer';
|
||||
|
|
|
@ -16,17 +16,11 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withUptimeGraphQL, UptimeGraphQLQueryProps } from '../../higher_order';
|
||||
import { monitorStatesQuery } from '../../../queries/monitor_states_query';
|
||||
import {
|
||||
MonitorSummary,
|
||||
MonitorSummaryResult,
|
||||
SummaryHistogramPoint,
|
||||
} from '../../../../common/graphql/types';
|
||||
import { HistogramPoint, FetchMonitorStatesQueryArgs } from '../../../../common/runtime_types';
|
||||
import { MonitorSummary } from '../../../../common/runtime_types';
|
||||
import { MonitorListStatusColumn } from './monitor_list_status_column';
|
||||
import { formatUptimeGraphQLErrorList } from '../../../lib/helper/format_error_list';
|
||||
import { ExpandedRowMap } from './types';
|
||||
import { MonitorBarSeries } from '../charts';
|
||||
import { MonitorPageLink } from './monitor_page_link';
|
||||
|
@ -34,36 +28,69 @@ import { OverviewPageLink } from './overview_page_link';
|
|||
import * as labels from './translations';
|
||||
import { MonitorListDrawer } from '../../connected';
|
||||
import { MonitorListPageSizeSelect } from './monitor_list_page_size_select';
|
||||
import { MonitorListProps } from '../../connected/monitor/monitor_list';
|
||||
import { MonitorList } from '../../../state/reducers/monitor_list';
|
||||
import { useUrlParams } from '../../../hooks';
|
||||
|
||||
interface MonitorListQueryResult {
|
||||
monitorStates?: MonitorSummaryResult;
|
||||
interface Props extends MonitorListProps {
|
||||
lastRefresh: number;
|
||||
monitorList: MonitorList;
|
||||
getMonitorList: (params: FetchMonitorStatesQueryArgs) => void;
|
||||
}
|
||||
|
||||
interface MonitorListProps {
|
||||
dangerColor: string;
|
||||
hasActiveFilters: boolean;
|
||||
successColor: string;
|
||||
linkParameters?: string;
|
||||
pageSize: number;
|
||||
setPageSize: (size: number) => void;
|
||||
}
|
||||
|
||||
type Props = UptimeGraphQLQueryProps<MonitorListQueryResult> & MonitorListProps;
|
||||
|
||||
const TruncatedEuiLink = styled(EuiLink)`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
export const MonitorListComponent = (props: Props) => {
|
||||
const { dangerColor, data, errors, hasActiveFilters, linkParameters, loading } = props;
|
||||
const DEFAULT_PAGE_SIZE = 10;
|
||||
const LOCAL_STORAGE_KEY = 'xpack.uptime.monitorList.pageSize';
|
||||
const getPageSizeValue = () => {
|
||||
const value = parseInt(localStorage.getItem(LOCAL_STORAGE_KEY) ?? '', 10);
|
||||
if (isNaN(value)) {
|
||||
return DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export const MonitorListComponent: React.FC<Props> = ({
|
||||
filters,
|
||||
getMonitorList,
|
||||
lastRefresh,
|
||||
monitorList: { list, error, loading },
|
||||
linkParameters,
|
||||
}) => {
|
||||
const [pageSize, setPageSize] = useState<number>(getPageSizeValue());
|
||||
const [drawerIds, updateDrawerIds] = useState<string[]>([]);
|
||||
|
||||
const items = data?.monitorStates?.summaries ?? [];
|
||||
const [getUrlValues] = useUrlParams();
|
||||
const { dateRangeStart, dateRangeEnd, pagination, statusFilter } = getUrlValues();
|
||||
|
||||
const nextPagePagination = data?.monitorStates?.nextPagePagination ?? '';
|
||||
const prevPagePagination = data?.monitorStates?.prevPagePagination ?? '';
|
||||
useEffect(() => {
|
||||
getMonitorList({
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
filters,
|
||||
pageSize,
|
||||
pagination,
|
||||
statusFilter,
|
||||
});
|
||||
}, [
|
||||
getMonitorList,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
filters,
|
||||
lastRefresh,
|
||||
pageSize,
|
||||
pagination,
|
||||
statusFilter,
|
||||
]);
|
||||
|
||||
const items = list.summaries ?? [];
|
||||
|
||||
const nextPagePagination = list.nextPagePagination ?? '';
|
||||
const prevPagePagination = list.prevPagePagination ?? '';
|
||||
|
||||
const getExpandedRowMap = () => {
|
||||
return drawerIds.reduce((map: ExpandedRowMap, id: string) => {
|
||||
|
@ -123,8 +150,8 @@ export const MonitorListComponent = (props: Props) => {
|
|||
mobileOptions: {
|
||||
show: false,
|
||||
},
|
||||
render: (histogramSeries: SummaryHistogramPoint[] | null) => (
|
||||
<MonitorBarSeries dangerColor={dangerColor} histogramSeries={histogramSeries} />
|
||||
render: (histogramSeries: HistogramPoint[] | null) => (
|
||||
<MonitorBarSeries histogramSeries={histogramSeries} />
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -153,70 +180,61 @@ export const MonitorListComponent = (props: Props) => {
|
|||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPanel>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
defaultMessage="Monitor status"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiBasicTable
|
||||
aria-label={labels.getDescriptionLabel(items.length)}
|
||||
error={errors ? formatUptimeGraphQLErrorList(errors) : errors}
|
||||
// Only set loading to true when there are no items present to prevent the bug outlined in
|
||||
// in https://github.com/elastic/eui/issues/2393 . Once that is fixed we can simply set the value here to
|
||||
// loading={loading}
|
||||
loading={loading && (!items || items.length < 1)}
|
||||
isExpandable={true}
|
||||
hasActions={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={getExpandedRowMap()}
|
||||
items={items}
|
||||
// TODO: not needed without sorting and pagination
|
||||
// onChange={onChange}
|
||||
noItemsMessage={
|
||||
hasActiveFilters ? labels.NO_MONITOR_ITEM_SELECTED : labels.NO_DATA_MESSAGE
|
||||
}
|
||||
// TODO: reintegrate pagination in future release
|
||||
// pagination={pagination}
|
||||
// TODO: reintegrate sorting in future release
|
||||
// sorting={sorting}
|
||||
columns={columns}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<MonitorListPageSizeSelect size={props.pageSize} setSize={props.setPageSize} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination={prevPagePagination}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination={nextPagePagination}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</>
|
||||
<EuiPanel>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorList.monitoringStatusTitle"
|
||||
defaultMessage="Monitor status"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiBasicTable
|
||||
aria-label={labels.getDescriptionLabel(items.length)}
|
||||
error={error?.message}
|
||||
// Only set loading to true when there are no items present to prevent the bug outlined in
|
||||
// in https://github.com/elastic/eui/issues/2393 . Once that is fixed we can simply set the value here to
|
||||
// loading={loading}
|
||||
loading={loading && (!items || items.length < 1)}
|
||||
isExpandable={true}
|
||||
hasActions={true}
|
||||
itemId="monitor_id"
|
||||
itemIdToExpandedRowMap={getExpandedRowMap()}
|
||||
items={items}
|
||||
// TODO: not needed without sorting and pagination
|
||||
// onChange={onChange}
|
||||
noItemsMessage={!!filters ? labels.NO_MONITOR_ITEM_SELECTED : labels.NO_DATA_MESSAGE}
|
||||
// TODO: reintegrate pagination in future release
|
||||
// pagination={pagination}
|
||||
// TODO: reintegrate sorting in future release
|
||||
// sorting={sorting}
|
||||
columns={columns}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<MonitorListPageSizeSelect size={pageSize} setSize={setPageSize} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.prevButton"
|
||||
direction="prev"
|
||||
pagination={prevPagePagination}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<OverviewPageLink
|
||||
dataTestSubj="xpack.uptime.monitorList.nextButton"
|
||||
direction="next"
|
||||
pagination={nextPagePagination}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
||||
export const MonitorList = withUptimeGraphQL<MonitorListQueryResult, MonitorListProps>(
|
||||
MonitorListComponent,
|
||||
monitorStatesQuery
|
||||
);
|
||||
|
|
|
@ -71,21 +71,21 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are
|
|||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "121",
|
||||
"timestamp": 121,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.2",
|
||||
"status": "down",
|
||||
},
|
||||
"timestamp": "123",
|
||||
"timestamp": 123,
|
||||
},
|
||||
Object {
|
||||
"monitor": Object {
|
||||
"ip": "127.0.0.3",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "125",
|
||||
"timestamp": 125,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
|
@ -175,7 +175,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there is o
|
|||
"ip": "127.0.0.1",
|
||||
"status": "up",
|
||||
},
|
||||
"timestamp": "121",
|
||||
"timestamp": 121,
|
||||
},
|
||||
],
|
||||
"summary": Object {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { MonitorSummary } from '../../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../../common/runtime_types';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { IntegrationGroup } from '../integration_group';
|
||||
|
||||
|
@ -19,6 +19,7 @@ describe('IntegrationGroup', () => {
|
|||
summary: {},
|
||||
checks: [],
|
||||
timestamp: '123',
|
||||
url: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import 'jest';
|
||||
import { MonitorSummary, Check } from '../../../../../../common/graphql/types';
|
||||
import React from 'react';
|
||||
import { MonitorListDrawerComponent } from '../monitor_list_drawer';
|
||||
import { MonitorDetails } from '../../../../../../common/runtime_types';
|
||||
import { Check, MonitorDetails, MonitorSummary } from '../../../../../../common/runtime_types';
|
||||
import { shallowWithRouter } from '../../../../../lib';
|
||||
|
||||
describe('MonitorListDrawer component', () => {
|
||||
|
@ -24,7 +23,7 @@ describe('MonitorListDrawer component', () => {
|
|||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '121',
|
||||
timestamp: 121,
|
||||
},
|
||||
],
|
||||
summary: {
|
||||
|
@ -77,21 +76,21 @@ describe('MonitorListDrawer component', () => {
|
|||
ip: '127.0.0.1',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '121',
|
||||
timestamp: 121,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.2',
|
||||
status: 'down',
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
ip: '127.0.0.3',
|
||||
status: 'up',
|
||||
},
|
||||
timestamp: '125',
|
||||
timestamp: 125,
|
||||
},
|
||||
];
|
||||
summary.state.checks = checks;
|
||||
|
|
|
@ -8,7 +8,7 @@ import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
|||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { MonitorStatusList } from '../monitor_status_list';
|
||||
import { Check } from '../../../../../../common/graphql/types';
|
||||
import { Check } from '../../../../../../common/runtime_types';
|
||||
|
||||
describe('MonitorStatusList component', () => {
|
||||
let checks: Check[];
|
||||
|
@ -21,110 +21,92 @@ describe('MonitorStatusList component', () => {
|
|||
beforeEach(() => {
|
||||
checks = [
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
monitor: {
|
||||
ip: '151.101.130.217',
|
||||
name: 'elastic',
|
||||
status: 'up',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
monitor: {
|
||||
ip: '151.101.194.217',
|
||||
name: 'elastic',
|
||||
status: 'up',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
monitor: {
|
||||
ip: '151.101.2.217',
|
||||
name: 'elastic',
|
||||
status: 'up',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '151.101.66.217',
|
||||
name: 'elastic',
|
||||
status: 'up',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '2a04:4e42:200::729',
|
||||
name: 'elastic',
|
||||
status: 'down',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '2a04:4e42:400::729',
|
||||
name: 'elastic',
|
||||
status: 'down',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '2a04:4e42:600::729',
|
||||
name: 'elastic',
|
||||
status: 'down',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
{
|
||||
agent: { id: '8f9a37fb-573a-4fdc-9895-440a5b39c250' },
|
||||
container: null,
|
||||
kubernetes: null,
|
||||
monitor: {
|
||||
ip: '2a04:4e42::729',
|
||||
name: 'elastic',
|
||||
status: 'down',
|
||||
},
|
||||
observer: {
|
||||
geo: { name: null, location: null },
|
||||
geo: {},
|
||||
},
|
||||
timestamp: '1570538236414',
|
||||
timestamp: 1570538236414,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
getLoggingIpHref,
|
||||
getLoggingKubernetesHref,
|
||||
} from '../../../../lib/helper';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../common/runtime_types';
|
||||
import { UptimeSettingsContext } from '../../../../contexts';
|
||||
|
||||
interface IntegrationGroupProps {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import { EuiPopover, EuiButton } from '@elastic/eui';
|
||||
import { IntegrationGroup } from './integration_group';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../common/runtime_types';
|
||||
import { toggleIntegrationsPopover, PopoverState } from '../../../../state/actions';
|
||||
|
||||
interface MonitorListActionsPopoverProps {
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiLink, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MostRecentError } from './most_recent_error';
|
||||
import { MonitorStatusList } from './monitor_status_list';
|
||||
import { MonitorDetails } from '../../../../../common/runtime_types';
|
||||
import { MonitorDetails, MonitorSummary } from '../../../../../common/runtime_types';
|
||||
import { MonitorListActionsPopover } from '../../../connected';
|
||||
|
||||
const ContainerDiv = styled.div`
|
||||
|
|
|
@ -8,9 +8,9 @@ import React from 'react';
|
|||
import { get, capitalize } from 'lodash';
|
||||
import { EuiCallOut, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { Check } from '../../../../../common/graphql/types';
|
||||
import { LocationLink } from './location_link';
|
||||
import { MonitorStatusRow } from './monitor_status_row';
|
||||
import { Check } from '../../../../../common/runtime_types';
|
||||
import { STATUS, UNNAMED_LOCATION } from '../../../../../common/constants';
|
||||
|
||||
interface MonitorStatusListProps {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { capitalize } from 'lodash';
|
|||
import styled from 'styled-components';
|
||||
import { EuiHealth, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui';
|
||||
import { parseTimestamp } from './parse_timestamp';
|
||||
import { Check } from '../../../../common/graphql/types';
|
||||
import { Check } from '../../../../common/runtime_types';
|
||||
import {
|
||||
STATUS,
|
||||
SHORT_TIMESPAN_LOCALE,
|
||||
|
|
|
@ -4,5 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { UptimeGraphQLQueryProps, withUptimeGraphQL } from './uptime_graphql_query';
|
||||
export { ResponsiveWrapperProps, withResponsiveWrapper } from './responsive_wrapper';
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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 { OperationVariables } from 'apollo-client';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import React, { Fragment, useContext, useEffect, useState } from 'react';
|
||||
import { withApollo, WithApolloClient } from 'react-apollo';
|
||||
import { formatUptimeGraphQLErrorList } from '../../lib/helper/format_error_list';
|
||||
import { UptimeRefreshContext } from '../../contexts';
|
||||
|
||||
export interface UptimeGraphQLQueryProps<T> {
|
||||
loading: boolean;
|
||||
data?: T;
|
||||
errors?: GraphQLError[];
|
||||
}
|
||||
|
||||
interface UptimeGraphQLProps {
|
||||
implementsCustomErrorState?: boolean;
|
||||
variables: OperationVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* This HOC abstracts the task of querying our GraphQL endpoint,
|
||||
* which eliminates the need for a lot of boilerplate code in the other components.
|
||||
*
|
||||
* @type T - the expected result's type
|
||||
* @type P - any props the wrapped component will require
|
||||
* @param WrappedComponent - the consuming component
|
||||
* @param query - the graphQL query
|
||||
*/
|
||||
export function withUptimeGraphQL<T, P = {}>(WrappedComponent: any, query: any) {
|
||||
type Props = UptimeGraphQLProps & WithApolloClient<T> & P;
|
||||
|
||||
return withApollo((props: Props) => {
|
||||
const { lastRefresh } = useContext(UptimeRefreshContext);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [data, setData] = useState<T | undefined>(undefined);
|
||||
const [errors, setErrors] = useState<GraphQLError[] | undefined>(undefined);
|
||||
let updateState = (
|
||||
loadingVal: boolean,
|
||||
dataVal: T | undefined,
|
||||
errorsVal: GraphQLError[] | undefined
|
||||
) => {
|
||||
setLoading(loadingVal);
|
||||
setData(dataVal);
|
||||
setErrors(errorsVal);
|
||||
};
|
||||
const { client, implementsCustomErrorState, variables } = props;
|
||||
const fetch = () => {
|
||||
setLoading(true);
|
||||
client
|
||||
.query<T>({ fetchPolicy: 'network-only', query, variables })
|
||||
.then(
|
||||
(result: any) => {
|
||||
updateState(result.loading, result.data, result.errors);
|
||||
},
|
||||
(result: any) => {
|
||||
updateState(false, undefined, result.graphQLErrors);
|
||||
}
|
||||
);
|
||||
};
|
||||
useEffect(() => {
|
||||
fetch();
|
||||
|
||||
/**
|
||||
* If the `then` handler in `fetch`'s promise is fired after
|
||||
* this component has unmounted, it will try to set state on an
|
||||
* unmounted component, which indicates a memory leak and will trigger
|
||||
* React warnings.
|
||||
*
|
||||
* We counteract this side effect by providing a cleanup function that will
|
||||
* reassign the update function to do nothing with the returned values.
|
||||
*/
|
||||
return () => {
|
||||
// this component is planned to be deprecated, for the time being
|
||||
// we will want to preserve this for the reason above.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
updateState = () => {};
|
||||
};
|
||||
}, [variables, lastRefresh]);
|
||||
if (!implementsCustomErrorState && errors && errors.length > 0) {
|
||||
return <Fragment>{formatUptimeGraphQLErrorList(errors)}</Fragment>;
|
||||
}
|
||||
return <WrappedComponent {...props} loading={loading} data={data} errors={errors} />;
|
||||
});
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* 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 { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { CreateGraphQLClient } from './framework_adapter_types';
|
||||
|
||||
export const createApolloClient: CreateGraphQLClient = (uri: string, xsrfHeader: string) =>
|
||||
new ApolloClient({
|
||||
link: new HttpLink({ uri, credentials: 'same-origin', headers: { 'kbn-xsrf': xsrfHeader } }),
|
||||
cache: new InMemoryCache({ dataIdFromObject: () => undefined }),
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* 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 { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
|
||||
export type GraphQLClient = ApolloClient<NormalizedCacheObject>;
|
||||
|
||||
export type CreateGraphQLClient = (url: string, xsrfHeader: string) => GraphQLClient;
|
|
@ -20,7 +20,6 @@ import {
|
|||
DEFAULT_TIMEPICKER_QUICK_RANGES,
|
||||
} from '../../../../common/constants';
|
||||
import { UMFrameworkAdapter } from '../../lib';
|
||||
import { createApolloClient } from './apollo_client_adapter';
|
||||
|
||||
export const getKibanaFrameworkAdapter = (
|
||||
core: CoreStart,
|
||||
|
@ -60,7 +59,6 @@ export const getKibanaFrameworkAdapter = (
|
|||
const props: UptimeAppProps = {
|
||||
basePath: basePath.get(),
|
||||
canSave,
|
||||
client: createApolloClient(`${basePath.get()}/api/uptime/graphql`, 'true'),
|
||||
core,
|
||||
darkMode: core.uiSettings.get(DEFAULT_DARK_MODE),
|
||||
commonlyUsedRanges: core.uiSettings.get(DEFAULT_TIMEPICKER_QUICK_RANGES),
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`formatErrorString returns a formatted string containing each error 1`] = `
|
||||
"Error: foo is bar
|
||||
Error: bar is not foo
|
||||
"
|
||||
`;
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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 { formatUptimeGraphQLErrorList } from '../format_error_list';
|
||||
|
||||
describe('formatErrorString', () => {
|
||||
it('returns an empty string for empty array', () => {
|
||||
const result = formatUptimeGraphQLErrorList([]);
|
||||
expect(result).toEqual('');
|
||||
});
|
||||
it('returns a formatted string containing each error', () => {
|
||||
const result = formatUptimeGraphQLErrorList([
|
||||
{
|
||||
message: 'foo is bar',
|
||||
locations: undefined,
|
||||
path: undefined,
|
||||
nodes: undefined,
|
||||
source: undefined,
|
||||
positions: undefined,
|
||||
originalError: undefined,
|
||||
extensions: undefined,
|
||||
name: 'test error',
|
||||
},
|
||||
{
|
||||
message: 'bar is not foo',
|
||||
locations: undefined,
|
||||
path: undefined,
|
||||
nodes: undefined,
|
||||
source: undefined,
|
||||
positions: undefined,
|
||||
originalError: undefined,
|
||||
extensions: undefined,
|
||||
name: 'test error',
|
||||
},
|
||||
]);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { GraphQLError } from 'graphql';
|
||||
|
||||
export const formatUptimeGraphQLErrorList = (errors: GraphQLError[]) =>
|
||||
errors.reduce(
|
||||
(errorString, error) =>
|
||||
errorString.concat(
|
||||
`${i18n.translate('xpack.uptime.errorMessage', {
|
||||
values: { message: error.message },
|
||||
defaultMessage: 'Error: {message}',
|
||||
})}\n`
|
||||
),
|
||||
''
|
||||
);
|
|
@ -1,5 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getApmHref creates href with base path when present 1`] = `"foo/app/apm#/services?kuery=url.domain:%20%22www.elastic.co%22&rangeFrom=now-15m&rangeTo=now"`;
|
||||
|
||||
exports[`getApmHref does not add a base path or extra slash when base path is empty string 1`] = `"/app/apm#/services?kuery=url.domain:%20%22www.elastic.co%22&rangeFrom=now-15m&rangeTo=now"`;
|
|
@ -1,19 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getInfraHref getInfraContainerHref creates a link for valid parameters 1`] = `"foo/app/metrics/link-to/container-detail/test-container-id"`;
|
||||
|
||||
exports[`getInfraHref getInfraContainerHref does not specify a base path when none is available 1`] = `"/app/metrics/link-to/container-detail/test-container-id"`;
|
||||
|
||||
exports[`getInfraHref getInfraContainerHref returns the first item when multiple container ids are supplied 1`] = `"bar/app/metrics/link-to/container-detail/test-container-id"`;
|
||||
|
||||
exports[`getInfraHref getInfraIpHref creates a link for valid parameters 1`] = `"bar/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`;
|
||||
|
||||
exports[`getInfraHref getInfraIpHref does not specify a base path when none is available 1`] = `"/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`;
|
||||
|
||||
exports[`getInfraHref getInfraIpHref returns a url for ors between multiple ips 1`] = `"foo/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20152.151.23.192%20or%20host.ip%20%3A%20151.101.202.217',kind:kuery)"`;
|
||||
|
||||
exports[`getInfraHref getInfraKubernetesHref creates a link for valid parameters 1`] = `"foo/app/metrics/link-to/pod-detail/test-pod-uid"`;
|
||||
|
||||
exports[`getInfraHref getInfraKubernetesHref does not specify a base path when none is available 1`] = `"/app/metrics/link-to/pod-detail/test-pod-uid"`;
|
||||
|
||||
exports[`getInfraHref getInfraKubernetesHref selects the first pod uid when there are multiple 1`] = `"/app/metrics/link-to/pod-detail/test-pod-uid"`;
|
|
@ -1,13 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getLoggingHref creates a container href with base path when present 1`] = `"bar/app/logs?logFilter=(expression:'container.id%20:%20test-container-id',kind:kuery)"`;
|
||||
|
||||
exports[`getLoggingHref creates a container href without a base path if it's an empty string 1`] = `"/app/logs?logFilter=(expression:'container.id%20:%20test-container-id',kind:kuery)"`;
|
||||
|
||||
exports[`getLoggingHref creates a pod href with base path when present 1`] = `"bar/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`;
|
||||
|
||||
exports[`getLoggingHref creates a pod href without a base path when it's an empty string 1`] = `"/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`;
|
||||
|
||||
exports[`getLoggingHref creates an ip href with base path when present 1`] = `"bar/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`;
|
||||
|
||||
exports[`getLoggingHref creates an ip href without a base path when it's an empty string 1`] = `"/app/logs?logFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`;
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { getApmHref } from '../get_apm_href';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../common/runtime_types';
|
||||
|
||||
describe('getApmHref', () => {
|
||||
let summary: MonitorSummary;
|
||||
|
@ -29,7 +29,7 @@ describe('getApmHref', () => {
|
|||
uid: 'test-pod-id',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
],
|
||||
timestamp: '123',
|
||||
|
@ -43,11 +43,15 @@ describe('getApmHref', () => {
|
|||
|
||||
it('creates href with base path when present', () => {
|
||||
const result = getApmHref(summary, 'foo', 'now-15m', 'now');
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"foo/app/apm#/services?kuery=url.domain:%20%22www.elastic.co%22&rangeFrom=now-15m&rangeTo=now"`
|
||||
);
|
||||
});
|
||||
|
||||
it('does not add a base path or extra slash when base path is empty string', () => {
|
||||
const result = getApmHref(summary, '', 'now-15m', 'now');
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"/app/apm#/services?kuery=url.domain:%20%22www.elastic.co%22&rangeFrom=now-15m&rangeTo=now"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { getInfraContainerHref, getInfraKubernetesHref, getInfraIpHref } from '../get_infra_href';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../common/runtime_types';
|
||||
|
||||
describe('getInfraHref', () => {
|
||||
let summary: MonitorSummary;
|
||||
|
@ -13,7 +13,6 @@ describe('getInfraHref', () => {
|
|||
summary = {
|
||||
monitor_id: 'foo',
|
||||
state: {
|
||||
summary: {},
|
||||
checks: [
|
||||
{
|
||||
monitor: {
|
||||
|
@ -28,9 +27,11 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
],
|
||||
summary: {},
|
||||
url: {},
|
||||
timestamp: '123',
|
||||
},
|
||||
};
|
||||
|
@ -38,11 +39,15 @@ describe('getInfraHref', () => {
|
|||
|
||||
it('getInfraContainerHref creates a link for valid parameters', () => {
|
||||
const result = getInfraContainerHref(summary, 'foo');
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"foo/app/metrics/link-to/container-detail/test-container-id"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraContainerHref does not specify a base path when none is available', () => {
|
||||
expect(getInfraContainerHref(summary, '')).toMatchSnapshot();
|
||||
expect(getInfraContainerHref(summary, '')).toMatchInlineSnapshot(
|
||||
`"/app/metrics/link-to/container-detail/test-container-id"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraContainerHref returns undefined when no container id is present', () => {
|
||||
|
@ -65,7 +70,7 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
|
@ -80,10 +85,12 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid-bar',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
];
|
||||
expect(getInfraContainerHref(summary, 'bar')).toMatchSnapshot();
|
||||
expect(getInfraContainerHref(summary, 'bar')).toMatchInlineSnapshot(
|
||||
`"bar/app/metrics/link-to/container-detail/test-container-id"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraContainerHref returns undefined when checks are undefined', () => {
|
||||
|
@ -94,11 +101,13 @@ describe('getInfraHref', () => {
|
|||
it('getInfraKubernetesHref creates a link for valid parameters', () => {
|
||||
const result = getInfraKubernetesHref(summary, 'foo');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(`"foo/app/metrics/link-to/pod-detail/test-pod-uid"`);
|
||||
});
|
||||
|
||||
it('getInfraKubernetesHref does not specify a base path when none is available', () => {
|
||||
expect(getInfraKubernetesHref(summary, '')).toMatchSnapshot();
|
||||
expect(getInfraKubernetesHref(summary, '')).toMatchInlineSnapshot(
|
||||
`"/app/metrics/link-to/pod-detail/test-pod-uid"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraKubernetesHref returns undefined when no pod data is present', () => {
|
||||
|
@ -121,7 +130,7 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
{
|
||||
monitor: {
|
||||
|
@ -136,10 +145,12 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid-bar',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
];
|
||||
expect(getInfraKubernetesHref(summary, '')).toMatchSnapshot();
|
||||
expect(getInfraKubernetesHref(summary, '')).toMatchInlineSnapshot(
|
||||
`"/app/metrics/link-to/pod-detail/test-pod-uid"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraKubernetesHref returns undefined when checks are undefined', () => {
|
||||
|
@ -148,17 +159,21 @@ describe('getInfraHref', () => {
|
|||
});
|
||||
|
||||
it('getInfraKubernetesHref returns undefined when checks are null', () => {
|
||||
summary.state.checks![0]!.kubernetes!.pod!.uid = null;
|
||||
delete summary.state.checks![0]!.kubernetes!.pod!.uid;
|
||||
expect(getInfraKubernetesHref(summary, '')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('getInfraIpHref creates a link for valid parameters', () => {
|
||||
const result = getInfraIpHref(summary, 'bar');
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"bar/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraIpHref does not specify a base path when none is available', () => {
|
||||
expect(getInfraIpHref(summary, '')).toMatchSnapshot();
|
||||
expect(getInfraIpHref(summary, '')).toMatchInlineSnapshot(
|
||||
`"/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraIpHref returns undefined when ip is undefined', () => {
|
||||
|
@ -167,14 +182,14 @@ describe('getInfraHref', () => {
|
|||
});
|
||||
|
||||
it('getInfraIpHref returns undefined when ip is null', () => {
|
||||
summary.state.checks![0].monitor.ip = null;
|
||||
delete summary.state.checks![0].monitor.ip;
|
||||
expect(getInfraIpHref(summary, 'foo')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('getInfraIpHref returns a url for ors between multiple ips', () => {
|
||||
summary.state.checks = [
|
||||
{
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
monitor: {
|
||||
ip: '152.151.23.192',
|
||||
status: 'up',
|
||||
|
@ -193,10 +208,12 @@ describe('getInfraHref', () => {
|
|||
uid: 'test-pod-uid',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
];
|
||||
expect(getInfraIpHref(summary, 'foo')).toMatchSnapshot();
|
||||
expect(getInfraIpHref(summary, 'foo')).toMatchInlineSnapshot(
|
||||
`"foo/app/metrics/inventory?waffleFilter=(expression:'host.ip%20%3A%20152.151.23.192%20or%20host.ip%20%3A%20151.101.202.217',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it('getInfraIpHref returns undefined if checks are undefined', () => {
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
getLoggingKubernetesHref,
|
||||
getLoggingIpHref,
|
||||
} from '../get_logging_href';
|
||||
import { MonitorSummary } from '../../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../common/runtime_types';
|
||||
|
||||
describe('getLoggingHref', () => {
|
||||
let summary: MonitorSummary;
|
||||
|
@ -33,10 +33,11 @@ describe('getLoggingHref', () => {
|
|||
uid: 'test-pod-id',
|
||||
},
|
||||
},
|
||||
timestamp: '123',
|
||||
timestamp: 123,
|
||||
},
|
||||
],
|
||||
timestamp: '123',
|
||||
url: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -44,37 +45,49 @@ describe('getLoggingHref', () => {
|
|||
it('creates a container href with base path when present', () => {
|
||||
const result = getLoggingContainerHref(summary, 'bar');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"bar/app/logs?logFilter=(expression:'container.id%20:%20test-container-id',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`creates a container href without a base path if it's an empty string`, () => {
|
||||
const result = getLoggingContainerHref(summary, '');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"/app/logs?logFilter=(expression:'container.id%20:%20test-container-id',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`creates an ip href with base path when present`, () => {
|
||||
const result = getLoggingKubernetesHref(summary, 'bar');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"bar/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it('creates a pod href with base path when present', () => {
|
||||
const result = getLoggingKubernetesHref(summary, 'bar');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"bar/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`creates a pod href without a base path when it's an empty string`, () => {
|
||||
const result = getLoggingKubernetesHref(summary, '');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"/app/logs?logFilter=(expression:'pod.uid%20:%20test-pod-id',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`creates an ip href without a base path when it's an empty string`, () => {
|
||||
const result = getLoggingIpHref(summary, '');
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).toMatchSnapshot();
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`"/app/logs?logFilter=(expression:'host.ip%20%3A%20151.101.202.217',kind:kuery)"`
|
||||
);
|
||||
});
|
||||
|
||||
it('returns undefined if necessary container is not present', () => {
|
||||
|
@ -83,7 +96,7 @@ describe('getLoggingHref', () => {
|
|||
});
|
||||
|
||||
it('returns undefined if necessary container is null', () => {
|
||||
summary.state.checks![0].container!.id = null;
|
||||
delete summary.state.checks![0].container!.id;
|
||||
expect(getLoggingContainerHref(summary, '')).toBeUndefined();
|
||||
});
|
||||
|
||||
|
@ -93,7 +106,7 @@ describe('getLoggingHref', () => {
|
|||
});
|
||||
|
||||
it('returns undefined if necessary pod is null', () => {
|
||||
summary.state.checks![0].kubernetes!.pod!.uid = null;
|
||||
delete summary.state.checks![0].kubernetes!.pod!.uid;
|
||||
expect(getLoggingKubernetesHref(summary, '')).toBeUndefined();
|
||||
});
|
||||
|
||||
|
@ -103,7 +116,7 @@ describe('getLoggingHref', () => {
|
|||
});
|
||||
|
||||
it('returns undefined ip href if ip is null', () => {
|
||||
summary.state.checks![0].monitor.ip = null;
|
||||
delete summary.state.checks![0].monitor.ip;
|
||||
expect(getLoggingIpHref(summary, '')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { Check } from '../../../../common/graphql/types';
|
||||
import { Check } from '../../../../common/runtime_types';
|
||||
|
||||
/**
|
||||
* Builds URLs to the designated features by extracting values from the provided
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { get } from 'lodash';
|
||||
import { addBasePath } from './add_base_path';
|
||||
import { MonitorSummary } from '../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../common/runtime_types';
|
||||
|
||||
export const getApmHref = (
|
||||
summary: MonitorSummary,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { MonitorSummary } from '../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../common/runtime_types';
|
||||
import { addBasePath } from './add_base_path';
|
||||
import { buildHref } from './build_href';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { MonitorSummary } from '../../../../common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../common/runtime_types';
|
||||
import { addBasePath } from './add_base_path';
|
||||
import { buildHref } from './build_href';
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SummaryHistogramPoint } from '../../../common/graphql/types';
|
||||
import { HistogramPoint } from '../../../common/runtime_types';
|
||||
|
||||
export const seriesHasDownValues = (series: SummaryHistogramPoint[] | null): boolean => {
|
||||
export const seriesHasDownValues = (series: HistogramPoint[] | null): boolean => {
|
||||
return series ? series.some(point => !!point.down) : false;
|
||||
};
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
||||
import ApolloClient from 'apollo-client';
|
||||
import React from 'react';
|
||||
import { ReactElement } from 'react';
|
||||
import { ChromeBreadcrumb } from 'src/core/public';
|
||||
import { UMBadge } from '../badge';
|
||||
import { UptimeAppProps } from '../uptime_app';
|
||||
|
@ -19,9 +17,7 @@ export type UMUpdateBreadcrumbs = (breadcrumbs: ChromeBreadcrumb[]) => void;
|
|||
|
||||
export type UMUpdateBadge = (badge: UMBadge) => void;
|
||||
|
||||
export type UMGraphQLClient = ApolloClient<NormalizedCacheObject>; // | OtherClientType
|
||||
|
||||
export type BootstrapUptimeApp = (props: UptimeAppProps) => React.ReactElement<any>;
|
||||
export type BootstrapUptimeApp = (props: UptimeAppProps) => ReactElement<any>;
|
||||
|
||||
export interface UMFrameworkAdapter {
|
||||
render(element: any): void;
|
||||
|
|
|
@ -5,20 +5,15 @@
|
|||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
MonitorList,
|
||||
OverviewPageParsingErrorCallout,
|
||||
StatusPanel,
|
||||
} from '../components/functional';
|
||||
import { OverviewPageParsingErrorCallout, StatusPanel } from '../components/functional';
|
||||
import { useUptimeTelemetry, UptimePage, useGetUrlParams } from '../hooks';
|
||||
import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
|
||||
import { useTrackPageview } from '../../../../../plugins/observability/public';
|
||||
import { DataPublicPluginSetup, IIndexPattern } from '../../../../../../src/plugins/data/public';
|
||||
import { UptimeThemeContext } from '../contexts';
|
||||
import { EmptyState, FilterGroup, KueryBar } from '../components/connected';
|
||||
import { EmptyState, FilterGroup, KueryBar, MonitorList } from '../components/connected';
|
||||
import { useUpdateKueryString } from '../hooks';
|
||||
import { PageHeader } from './page_header';
|
||||
import { useBreadcrumbs } from '../hooks/use_breadcrumbs';
|
||||
|
@ -40,34 +35,9 @@ const EuiFlexItemStyled = styled(EuiFlexItem)`
|
|||
}
|
||||
`;
|
||||
|
||||
// TODO: these values belong deeper down in the monitor
|
||||
// list pagination control, but are here temporarily until we
|
||||
// are done removing GraphQL
|
||||
const DEFAULT_PAGE_SIZE = 10;
|
||||
const LOCAL_STORAGE_KEY = 'xpack.uptime.monitorList.pageSize';
|
||||
const getMonitorListPageSizeValue = () => {
|
||||
const value = parseInt(localStorage.getItem(LOCAL_STORAGE_KEY) ?? '', 10);
|
||||
if (isNaN(value)) {
|
||||
return DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFilters }: Props) => {
|
||||
const { colors } = useContext(UptimeThemeContext);
|
||||
// TODO: this is temporary until we migrate the monitor list to our Redux implementation
|
||||
const [monitorListPageSize, setMonitorListPageSize] = useState<number>(
|
||||
getMonitorListPageSizeValue()
|
||||
);
|
||||
const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = useGetUrlParams();
|
||||
const {
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
pagination,
|
||||
statusFilter,
|
||||
search,
|
||||
filters: urlFilters,
|
||||
} = params;
|
||||
const { search, filters: urlFilters } = params;
|
||||
|
||||
useUptimeTelemetry(UptimePage.Overview);
|
||||
|
||||
|
@ -80,13 +50,6 @@ export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFi
|
|||
setEsKueryFilters(esFilters ?? '');
|
||||
}, [esFilters, setEsKueryFilters]);
|
||||
|
||||
const sharedProps = {
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
statusFilter,
|
||||
filters: esFilters,
|
||||
};
|
||||
|
||||
const linkParameters = stringifyUrlParams(params, true);
|
||||
|
||||
const heading = i18n.translate('xpack.uptime.overviewPage.headerText', {
|
||||
|
@ -117,20 +80,7 @@ export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFi
|
|||
<EuiSpacer size="s" />
|
||||
<StatusPanel />
|
||||
<EuiSpacer size="s" />
|
||||
<MonitorList
|
||||
dangerColor={colors.danger}
|
||||
hasActiveFilters={!!esFilters}
|
||||
implementsCustomErrorState={true}
|
||||
linkParameters={linkParameters}
|
||||
pageSize={monitorListPageSize}
|
||||
setPageSize={setMonitorListPageSize}
|
||||
successColor={colors.success}
|
||||
variables={{
|
||||
...sharedProps,
|
||||
pagination,
|
||||
pageSize: monitorListPageSize,
|
||||
}}
|
||||
/>
|
||||
<MonitorList filters={esFilters} linkParameters={linkParameters} />
|
||||
</EmptyState>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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 gql from 'graphql-tag';
|
||||
|
||||
export const monitorStatesQueryString = `
|
||||
query MonitorStates($dateRangeStart: String!, $dateRangeEnd: String!, $pagination: String, $filters: String, $statusFilter: String, $pageSize: Int) {
|
||||
monitorStates: getMonitorStates(
|
||||
dateRangeStart: $dateRangeStart
|
||||
dateRangeEnd: $dateRangeEnd
|
||||
pagination: $pagination
|
||||
filters: $filters
|
||||
statusFilter: $statusFilter
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
prevPagePagination
|
||||
nextPagePagination
|
||||
totalSummaryCount
|
||||
summaries {
|
||||
monitor_id
|
||||
histogram {
|
||||
count
|
||||
points {
|
||||
timestamp
|
||||
up
|
||||
down
|
||||
}
|
||||
}
|
||||
state {
|
||||
agent {
|
||||
id
|
||||
}
|
||||
checks {
|
||||
agent {
|
||||
id
|
||||
}
|
||||
container {
|
||||
id
|
||||
}
|
||||
kubernetes {
|
||||
pod {
|
||||
uid
|
||||
}
|
||||
}
|
||||
monitor {
|
||||
ip
|
||||
name
|
||||
status
|
||||
}
|
||||
observer {
|
||||
geo {
|
||||
name
|
||||
location {
|
||||
lat
|
||||
lon
|
||||
}
|
||||
}
|
||||
}
|
||||
timestamp
|
||||
}
|
||||
geo {
|
||||
name
|
||||
location {
|
||||
lat
|
||||
lon
|
||||
}
|
||||
}
|
||||
observer {
|
||||
geo {
|
||||
name
|
||||
location {
|
||||
lat
|
||||
lon
|
||||
}
|
||||
}
|
||||
}
|
||||
monitor {
|
||||
id
|
||||
name
|
||||
status
|
||||
type
|
||||
}
|
||||
summary {
|
||||
up
|
||||
down
|
||||
geo {
|
||||
name
|
||||
location {
|
||||
lat
|
||||
lon
|
||||
}
|
||||
}
|
||||
}
|
||||
url {
|
||||
full
|
||||
domain
|
||||
}
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const monitorStatesQuery = gql`
|
||||
${monitorStatesQueryString}
|
||||
`;
|
|
@ -7,6 +7,7 @@
|
|||
export * from './overview_filters';
|
||||
export * from './snapshot';
|
||||
export * from './ui';
|
||||
export * from './monitor_list';
|
||||
export * from './monitor_status';
|
||||
export * from './index_patternts';
|
||||
export * from './ping';
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 { createAction } from 'redux-actions';
|
||||
import { FetchMonitorStatesQueryArgs, MonitorSummaryResult } from '../../../common/runtime_types';
|
||||
|
||||
export const getMonitorList = createAction<FetchMonitorStatesQueryArgs>('GET_MONITOR_LIST');
|
||||
export const getMonitorListSuccess = createAction<MonitorSummaryResult>('GET_MONITOR_LIST_SUCCESS');
|
||||
export const getMonitorListFailure = createAction<Error>('GET_MONITOR_LIST_FAIL');
|
|
@ -3,6 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
import { QueryParams } from './types';
|
||||
import { Ping } from '../../../common/runtime_types';
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
export * from './monitor';
|
||||
export * from './monitor_list';
|
||||
export * from './overview_filters';
|
||||
export * from './snapshot';
|
||||
export * from './monitor_status';
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 { API_URLS } from '../../../common/constants';
|
||||
import { apiService } from './utils';
|
||||
import {
|
||||
FetchMonitorStatesQueryArgs,
|
||||
MonitorSummaryResult,
|
||||
MonitorSummaryResultType,
|
||||
} from '../../../common/runtime_types';
|
||||
|
||||
export const fetchMonitorList = async (
|
||||
params: FetchMonitorStatesQueryArgs
|
||||
): Promise<MonitorSummaryResult> => {
|
||||
return await apiService.get(API_URLS.MONITOR_LIST, params, MonitorSummaryResultType);
|
||||
};
|
|
@ -8,6 +8,7 @@ import { fork } from 'redux-saga/effects';
|
|||
import { fetchMonitorDetailsEffect } from './monitor';
|
||||
import { fetchOverviewFiltersEffect } from './overview_filters';
|
||||
import { fetchSnapshotCountEffect } from './snapshot';
|
||||
import { fetchMonitorListEffect } from './monitor_list';
|
||||
import { fetchMonitorStatusEffect } from './monitor_status';
|
||||
import { fetchDynamicSettingsEffect, setDynamicSettingsEffect } from './dynamic_settings';
|
||||
import { fetchIndexPatternEffect } from './index_pattern';
|
||||
|
@ -20,6 +21,7 @@ export function* rootEffect() {
|
|||
yield fork(fetchMonitorDetailsEffect);
|
||||
yield fork(fetchSnapshotCountEffect);
|
||||
yield fork(fetchOverviewFiltersEffect);
|
||||
yield fork(fetchMonitorListEffect);
|
||||
yield fork(fetchMonitorStatusEffect);
|
||||
yield fork(fetchDynamicSettingsEffect);
|
||||
yield fork(setDynamicSettingsEffect);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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 { takeLatest } from 'redux-saga/effects';
|
||||
import { getMonitorList, getMonitorListSuccess, getMonitorListFailure } from '../actions';
|
||||
import { fetchMonitorList } from '../api';
|
||||
import { fetchEffectFactory } from './fetch_effect';
|
||||
|
||||
export function* fetchMonitorListEffect() {
|
||||
yield takeLatest(
|
||||
getMonitorList,
|
||||
fetchEffectFactory(fetchMonitorList, getMonitorListSuccess, getMonitorListFailure)
|
||||
);
|
||||
}
|
|
@ -10,6 +10,7 @@ import { overviewFiltersReducer } from './overview_filters';
|
|||
import { snapshotReducer } from './snapshot';
|
||||
import { uiReducer } from './ui';
|
||||
import { monitorStatusReducer } from './monitor_status';
|
||||
import { monitorListReducer } from './monitor_list';
|
||||
import { dynamicSettingsReducer } from './dynamic_settings';
|
||||
import { indexPatternReducer } from './index_pattern';
|
||||
import { pingReducer } from './ping';
|
||||
|
@ -23,6 +24,7 @@ export const rootReducer = combineReducers({
|
|||
overviewFilters: overviewFiltersReducer,
|
||||
snapshot: snapshotReducer,
|
||||
ui: uiReducer,
|
||||
monitorList: monitorListReducer,
|
||||
monitorStatus: monitorStatusReducer,
|
||||
dynamicSettings: dynamicSettingsReducer,
|
||||
indexPattern: indexPatternReducer,
|
||||
|
|
|
@ -24,9 +24,9 @@ const initialState: MonitorDuration = {
|
|||
errors: [],
|
||||
};
|
||||
|
||||
type PayLoad = MonitorDurationResult & Error;
|
||||
type Payload = MonitorDurationResult & Error;
|
||||
|
||||
export const monitorDurationReducer = handleActions<MonitorDuration, PayLoad>(
|
||||
export const monitorDurationReducer = handleActions<MonitorDuration, Payload>(
|
||||
{
|
||||
[String(getMonitorDurationAction)]: (state: MonitorDuration) => ({
|
||||
...state,
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 { handleActions, Action } from 'redux-actions';
|
||||
import { getMonitorList, getMonitorListSuccess, getMonitorListFailure } from '../actions';
|
||||
import { MonitorSummaryResult } from '../../../common/runtime_types';
|
||||
|
||||
export interface MonitorList {
|
||||
list: MonitorSummaryResult;
|
||||
error?: Error;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const initialState: MonitorList = {
|
||||
list: {
|
||||
nextPagePagination: null,
|
||||
prevPagePagination: null,
|
||||
summaries: [],
|
||||
totalSummaryCount: 0,
|
||||
},
|
||||
loading: false,
|
||||
};
|
||||
|
||||
type Payload = MonitorSummaryResult & Error;
|
||||
|
||||
export const monitorListReducer = handleActions<MonitorList, Payload>(
|
||||
{
|
||||
[String(getMonitorList)]: (state: MonitorList) => ({
|
||||
...state,
|
||||
loading: true,
|
||||
}),
|
||||
[String(getMonitorListSuccess)]: (
|
||||
state: MonitorList,
|
||||
action: Action<MonitorSummaryResult>
|
||||
) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
list: { ...action.payload },
|
||||
}),
|
||||
[String(getMonitorListFailure)]: (state: MonitorList, action: Action<Error>) => ({
|
||||
...state,
|
||||
error: action.payload,
|
||||
loading: false,
|
||||
}),
|
||||
},
|
||||
initialState
|
||||
);
|
|
@ -71,6 +71,15 @@ describe('state selectors', () => {
|
|||
loading: false,
|
||||
errors: [],
|
||||
},
|
||||
monitorList: {
|
||||
list: {
|
||||
prevPagePagination: null,
|
||||
nextPagePagination: null,
|
||||
summaries: [],
|
||||
totalSummaryCount: 0,
|
||||
},
|
||||
loading: false,
|
||||
},
|
||||
ml: {
|
||||
mlJob: {
|
||||
data: null,
|
||||
|
|
|
@ -92,3 +92,8 @@ export const selectMonitorStatusAlert = ({ indexPattern, overviewFilters, ui }:
|
|||
export const indexStatusSelector = ({ indexStatus }: AppState) => {
|
||||
return indexStatus.indexStatus;
|
||||
};
|
||||
|
||||
export const monitorListSelector = ({ monitorList, ui: { lastRefresh } }: AppState) => ({
|
||||
monitorList,
|
||||
lastRefresh,
|
||||
});
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
import { EuiPage, EuiErrorBoundary } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useEffect } from 'react';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { I18nStart, ChromeBreadcrumb, CoreStart } from 'src/core/public';
|
||||
import { PluginsSetup } from 'ui/new_platform/new_platform';
|
||||
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
|
||||
import { UMGraphQLClient, UMUpdateBadge } from './lib/lib';
|
||||
import { UMUpdateBadge } from './lib/lib';
|
||||
import {
|
||||
UptimeRefreshContextProvider,
|
||||
UptimeSettingsContextProvider,
|
||||
|
@ -39,7 +38,6 @@ export interface UptimeAppColors {
|
|||
export interface UptimeAppProps {
|
||||
basePath: string;
|
||||
canSave: boolean;
|
||||
client: UMGraphQLClient;
|
||||
core: CoreStart;
|
||||
darkMode: boolean;
|
||||
i18n: I18nStart;
|
||||
|
@ -59,7 +57,6 @@ const Application = (props: UptimeAppProps) => {
|
|||
const {
|
||||
basePath,
|
||||
canSave,
|
||||
client,
|
||||
core,
|
||||
darkMode,
|
||||
i18n: i18nCore,
|
||||
|
@ -97,25 +94,23 @@ const Application = (props: UptimeAppProps) => {
|
|||
<ReduxProvider store={store}>
|
||||
<KibanaContextProvider services={{ ...core, ...plugins }}>
|
||||
<Router basename={routerBasename}>
|
||||
<ApolloProvider client={client}>
|
||||
<UptimeRefreshContextProvider>
|
||||
<UptimeSettingsContextProvider {...props}>
|
||||
<UptimeThemeContextProvider darkMode={darkMode}>
|
||||
<UptimeAlertsContextProvider>
|
||||
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
|
||||
<main>
|
||||
<UptimeAlertsFlyoutWrapper
|
||||
alertTypeId="xpack.uptime.alerts.monitorStatus"
|
||||
canChangeTrigger={false}
|
||||
/>
|
||||
<PageRouter autocomplete={plugins.data.autocomplete} />
|
||||
</main>
|
||||
</EuiPage>
|
||||
</UptimeAlertsContextProvider>
|
||||
</UptimeThemeContextProvider>
|
||||
</UptimeSettingsContextProvider>
|
||||
</UptimeRefreshContextProvider>
|
||||
</ApolloProvider>
|
||||
<UptimeRefreshContextProvider>
|
||||
<UptimeSettingsContextProvider {...props}>
|
||||
<UptimeThemeContextProvider darkMode={darkMode}>
|
||||
<UptimeAlertsContextProvider>
|
||||
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
|
||||
<main>
|
||||
<UptimeAlertsFlyoutWrapper
|
||||
alertTypeId="xpack.uptime.alerts.monitorStatus"
|
||||
canChangeTrigger={false}
|
||||
/>
|
||||
<PageRouter autocomplete={plugins.data.autocomplete} />
|
||||
</main>
|
||||
</EuiPage>
|
||||
</UptimeAlertsContextProvider>
|
||||
</UptimeThemeContextProvider>
|
||||
</UptimeSettingsContextProvider>
|
||||
</UptimeRefreshContextProvider>
|
||||
</Router>
|
||||
</KibanaContextProvider>
|
||||
</ReduxProvider>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"flattenTypes": true,
|
||||
"generatorConfig": {},
|
||||
"primitives": {
|
||||
"String": "string",
|
||||
"Int": "number",
|
||||
"Float": "number",
|
||||
"Boolean": "boolean",
|
||||
"ID": "string"
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
require('../../../../../src/setup_node_env');
|
||||
|
||||
const { resolve } = require('path');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
|
||||
const { generate } = require('graphql-code-generator');
|
||||
|
||||
const CONFIG_PATH = resolve(__dirname, 'gql_gen.json');
|
||||
const OUTPUT_INTROSPECTION_PATH = resolve('common', 'graphql', 'introspection.json');
|
||||
const OUTPUT_TYPES_PATH = resolve('common', 'graphql', 'types.ts');
|
||||
const SCHEMA_PATH = resolve(__dirname, 'graphql_schemas.ts');
|
||||
|
||||
async function main() {
|
||||
await generate(
|
||||
{
|
||||
args: [],
|
||||
config: CONFIG_PATH,
|
||||
out: OUTPUT_INTROSPECTION_PATH,
|
||||
overwrite: true,
|
||||
schema: SCHEMA_PATH,
|
||||
template: 'graphql-codegen-introspection-template',
|
||||
},
|
||||
true
|
||||
);
|
||||
await generate(
|
||||
{
|
||||
args: [],
|
||||
config: CONFIG_PATH,
|
||||
out: OUTPUT_TYPES_PATH,
|
||||
overwrite: true,
|
||||
schema: SCHEMA_PATH,
|
||||
template: 'graphql-codegen-typescript-template',
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
|
@ -16241,7 +16241,6 @@
|
|||
"xpack.uptime.emptyStateError.notAuthorized": "アップタイムデータの表示が承認されていません。システム管理者にお問い合わせください。",
|
||||
"xpack.uptime.emptyStateError.notFoundPage": "ページが見つかりません",
|
||||
"xpack.uptime.emptyStateError.title": "エラー",
|
||||
"xpack.uptime.errorMessage": "エラー: {message}",
|
||||
"xpack.uptime.featureCatalogueDescription": "エンドポイントヘルスチェックとアップタイム監視を行います。",
|
||||
"xpack.uptime.featureRegistry.uptimeFeatureName": "アップタイム",
|
||||
"xpack.uptime.filterBar.ariaLabel": "概要ページのインプットフィルター基準",
|
||||
|
|
|
@ -16246,7 +16246,6 @@
|
|||
"xpack.uptime.emptyStateError.notAuthorized": "您无权查看 Uptime 数据,请联系系统管理员。",
|
||||
"xpack.uptime.emptyStateError.notFoundPage": "未找到页面",
|
||||
"xpack.uptime.emptyStateError.title": "错误",
|
||||
"xpack.uptime.errorMessage": "错误:{message}",
|
||||
"xpack.uptime.featureCatalogueDescription": "执行终端节点运行状况检查和运行时间监测。",
|
||||
"xpack.uptime.featureRegistry.uptimeFeatureName": "运行时间",
|
||||
"xpack.uptime.filterBar.ariaLabel": "概览页面的输入筛选条件",
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* 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 const DEFAULT_GRAPHQL_PATH = '/api/uptime/graphql';
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* 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 { createMonitorStatesResolvers, monitorStatesSchema } from './monitor_states';
|
||||
import { pingsSchema } from './pings';
|
||||
import { CreateUMGraphQLResolvers } from './types';
|
||||
import { unsignedIntegerResolverFunctions, unsignedIntegerSchema } from './unsigned_int_scalar';
|
||||
|
||||
export { DEFAULT_GRAPHQL_PATH } from './constants';
|
||||
export const resolvers: CreateUMGraphQLResolvers[] = [
|
||||
createMonitorStatesResolvers,
|
||||
unsignedIntegerResolverFunctions,
|
||||
];
|
||||
export const typeDefs: any[] = [pingsSchema, unsignedIntegerSchema, monitorStatesSchema];
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* 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 { createMonitorStatesResolvers } from './resolvers';
|
||||
export { monitorStatesSchema } from './schema.gql';
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* 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 { CreateUMGraphQLResolvers, UMContext } from '../types';
|
||||
import { UMServerLibs } from '../../lib/lib';
|
||||
import { UMResolver } from '../../../../../legacy/plugins/uptime/common/graphql/resolver_types';
|
||||
import {
|
||||
GetMonitorStatesQueryArgs,
|
||||
MonitorSummaryResult,
|
||||
} from '../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants';
|
||||
import { savedObjectsAdapter } from '../../lib/saved_objects';
|
||||
|
||||
export type UMGetMonitorStatesResolver = UMResolver<
|
||||
MonitorSummaryResult | Promise<MonitorSummaryResult>,
|
||||
any,
|
||||
GetMonitorStatesQueryArgs,
|
||||
UMContext
|
||||
>;
|
||||
|
||||
export const createMonitorStatesResolvers: CreateUMGraphQLResolvers = (
|
||||
libs: UMServerLibs
|
||||
): {
|
||||
Query: {
|
||||
getMonitorStates: UMGetMonitorStatesResolver;
|
||||
};
|
||||
} => {
|
||||
return {
|
||||
Query: {
|
||||
async getMonitorStates(
|
||||
_resolver,
|
||||
{ dateRangeStart, dateRangeEnd, filters, pagination, statusFilter, pageSize },
|
||||
{ APICaller, savedObjectsClient }
|
||||
): Promise<MonitorSummaryResult> {
|
||||
const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings(
|
||||
savedObjectsClient
|
||||
);
|
||||
|
||||
const decodedPagination = pagination
|
||||
? JSON.parse(decodeURIComponent(pagination))
|
||||
: CONTEXT_DEFAULTS.CURSOR_PAGINATION;
|
||||
const [
|
||||
indexStatus,
|
||||
{ summaries, nextPagePagination, prevPagePagination },
|
||||
] = await Promise.all([
|
||||
libs.requests.getIndexStatus({ callES: APICaller, dynamicSettings }),
|
||||
libs.requests.getMonitorStates({
|
||||
callES: APICaller,
|
||||
dynamicSettings,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
pagination: decodedPagination,
|
||||
pageSize,
|
||||
filters,
|
||||
// this is added to make typescript happy,
|
||||
// this sort of reassignment used to be further downstream but I've moved it here
|
||||
// because this code is going to be decomissioned soon
|
||||
statusFilter: statusFilter || undefined,
|
||||
}),
|
||||
]);
|
||||
|
||||
const totalSummaryCount = indexStatus?.docCount ?? 0;
|
||||
|
||||
return {
|
||||
summaries,
|
||||
nextPagePagination,
|
||||
prevPagePagination,
|
||||
totalSummaryCount,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* 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 gql from 'graphql-tag';
|
||||
|
||||
export const monitorStatesSchema = gql`
|
||||
"Represents a monitor's statuses for a period of time."
|
||||
type SummaryHistogramPoint {
|
||||
"The time at which these data were collected."
|
||||
timestamp: UnsignedInteger!
|
||||
"The number of _up_ documents."
|
||||
up: Int!
|
||||
"The number of _down_ documents."
|
||||
down: Int!
|
||||
}
|
||||
|
||||
"Monitor status data over time."
|
||||
type SummaryHistogram {
|
||||
"The number of documents used to assemble the histogram."
|
||||
count: Int!
|
||||
"The individual histogram data points."
|
||||
points: [SummaryHistogramPoint!]!
|
||||
}
|
||||
|
||||
type Agent {
|
||||
id: String!
|
||||
}
|
||||
|
||||
type Check {
|
||||
agent: Agent
|
||||
container: StateContainer
|
||||
kubernetes: StateKubernetes
|
||||
monitor: CheckMonitor!
|
||||
observer: CheckObserver
|
||||
timestamp: String!
|
||||
}
|
||||
|
||||
type StateContainer {
|
||||
id: String
|
||||
}
|
||||
|
||||
type StateKubernetes {
|
||||
pod: StatePod
|
||||
}
|
||||
|
||||
type StatePod {
|
||||
uid: String
|
||||
}
|
||||
|
||||
type CheckMonitor {
|
||||
ip: String
|
||||
name: String
|
||||
status: String!
|
||||
}
|
||||
|
||||
type Location {
|
||||
lat: Float
|
||||
lon: Float
|
||||
}
|
||||
|
||||
type CheckGeo {
|
||||
name: String
|
||||
location: Location
|
||||
}
|
||||
|
||||
type CheckObserver {
|
||||
geo: CheckGeo
|
||||
}
|
||||
|
||||
type StateGeo {
|
||||
name: [String]
|
||||
location: Location
|
||||
}
|
||||
|
||||
type StateObserver {
|
||||
geo: StateGeo
|
||||
}
|
||||
|
||||
type MonitorState {
|
||||
status: String
|
||||
name: String
|
||||
id: String
|
||||
type: String
|
||||
}
|
||||
|
||||
type Summary {
|
||||
up: Int
|
||||
down: Int
|
||||
geo: CheckGeo
|
||||
}
|
||||
|
||||
type MonitorSummaryUrl {
|
||||
domain: String
|
||||
fragment: String
|
||||
full: String
|
||||
original: String
|
||||
password: String
|
||||
path: String
|
||||
port: Int
|
||||
query: String
|
||||
scheme: String
|
||||
username: String
|
||||
}
|
||||
|
||||
type StateUrl {
|
||||
domain: String
|
||||
full: String
|
||||
path: String
|
||||
port: Int
|
||||
scheme: String
|
||||
}
|
||||
|
||||
"Contains monitor transmission encryption information."
|
||||
type StateTLS {
|
||||
"The date and time after which the certificate is invalid."
|
||||
certificate_not_valid_after: String
|
||||
certificate_not_valid_before: String
|
||||
certificates: String
|
||||
rtt: RTT
|
||||
}
|
||||
|
||||
"Unifies the subsequent data for an uptime monitor."
|
||||
type State {
|
||||
"The agent processing the monitor."
|
||||
agent: Agent
|
||||
"There is a check object for each instance of the monitoring agent."
|
||||
checks: [Check!]
|
||||
geo: StateGeo
|
||||
observer: StateObserver
|
||||
monitor: MonitorState
|
||||
summary: Summary!
|
||||
timestamp: UnsignedInteger!
|
||||
"Transport encryption information."
|
||||
tls: [StateTLS]
|
||||
url: StateUrl
|
||||
}
|
||||
|
||||
"Represents the current state and associated data for an Uptime monitor."
|
||||
type MonitorSummary {
|
||||
"The ID assigned by the config or generated by the user."
|
||||
monitor_id: String!
|
||||
"The state of the monitor and its associated details."
|
||||
state: State!
|
||||
histogram: SummaryHistogram
|
||||
}
|
||||
|
||||
"The primary object returned for monitor states."
|
||||
type MonitorSummaryResult {
|
||||
"Used to go to the next page of results"
|
||||
prevPagePagination: String
|
||||
"Used to go to the previous page of results"
|
||||
nextPagePagination: String
|
||||
"The objects representing the state of a series of heartbeat monitors."
|
||||
summaries: [MonitorSummary!]
|
||||
"The number of summaries."
|
||||
totalSummaryCount: Int!
|
||||
}
|
||||
|
||||
enum CursorDirection {
|
||||
AFTER
|
||||
BEFORE
|
||||
}
|
||||
|
||||
enum SortOrder {
|
||||
ASC
|
||||
DESC
|
||||
}
|
||||
|
||||
type Query {
|
||||
"Fetches the current state of Uptime monitors for the given parameters."
|
||||
getMonitorStates(
|
||||
dateRangeStart: String!
|
||||
dateRangeEnd: String!
|
||||
pagination: String
|
||||
filters: String
|
||||
statusFilter: String
|
||||
pageSize: Int
|
||||
): MonitorSummaryResult
|
||||
}
|
||||
`;
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* 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 { pingsSchema } from './schema.gql';
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* 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 gql from 'graphql-tag';
|
||||
|
||||
export const pingsSchema = gql`
|
||||
type PingResults {
|
||||
"Total number of matching pings"
|
||||
total: UnsignedInteger!
|
||||
"Unique list of all locations the query matched"
|
||||
locations: [String!]!
|
||||
"List of pings "
|
||||
pings: [Ping!]!
|
||||
}
|
||||
|
||||
type ContainerImage {
|
||||
name: String
|
||||
tag: String
|
||||
}
|
||||
|
||||
type Container {
|
||||
id: String
|
||||
image: ContainerImage
|
||||
name: String
|
||||
runtime: String
|
||||
}
|
||||
|
||||
type DocCount {
|
||||
count: UnsignedInteger!
|
||||
}
|
||||
|
||||
"The monitor's status for a ping"
|
||||
type Duration {
|
||||
us: UnsignedInteger
|
||||
}
|
||||
|
||||
"An agent for recording a beat"
|
||||
type Beat {
|
||||
hostname: String
|
||||
name: String
|
||||
timezone: String
|
||||
type: String
|
||||
}
|
||||
|
||||
type Docker {
|
||||
id: String
|
||||
image: String
|
||||
name: String
|
||||
}
|
||||
|
||||
type ECS {
|
||||
version: String
|
||||
}
|
||||
|
||||
type Error {
|
||||
code: Int
|
||||
message: String
|
||||
type: String
|
||||
}
|
||||
|
||||
type OS {
|
||||
family: String
|
||||
kernel: String
|
||||
platform: String
|
||||
version: String
|
||||
name: String
|
||||
build: String
|
||||
}
|
||||
|
||||
"Geolocation data added via processors to enrich events."
|
||||
type Geo {
|
||||
"Name of the city in which the agent is running."
|
||||
city_name: String
|
||||
"The name of the continent on which the agent is running."
|
||||
continent_name: String
|
||||
"ISO designation for the agent's country."
|
||||
country_iso_code: String
|
||||
"The name of the agent's country."
|
||||
country_name: String
|
||||
"The lat/long of the agent."
|
||||
location: String
|
||||
"A name for the host's location, e.g. 'us-east-1' or 'LAX'."
|
||||
name: String
|
||||
"ISO designation of the agent's region."
|
||||
region_iso_code: String
|
||||
"Name of the region hosting the agent."
|
||||
region_name: String
|
||||
}
|
||||
|
||||
type Host {
|
||||
architecture: String
|
||||
id: String
|
||||
hostname: String
|
||||
ip: String
|
||||
mac: String
|
||||
name: String
|
||||
os: OS
|
||||
}
|
||||
|
||||
type HttpRTT {
|
||||
content: Duration
|
||||
response_header: Duration
|
||||
total: Duration
|
||||
validate: Duration
|
||||
validate_body: Duration
|
||||
write_request: Duration
|
||||
}
|
||||
|
||||
type HTTPBody {
|
||||
"Size of HTTP response body in bytes"
|
||||
bytes: UnsignedInteger
|
||||
"Hash of the HTTP response body"
|
||||
hash: String
|
||||
"Response body of the HTTP Response. May be truncated based on client settings."
|
||||
content: String
|
||||
"Byte length of the content string, taking into account multibyte chars."
|
||||
content_bytes: UnsignedInteger
|
||||
}
|
||||
|
||||
type HTTPResponse {
|
||||
status_code: UnsignedInteger
|
||||
body: HTTPBody
|
||||
}
|
||||
|
||||
type HTTP {
|
||||
response: HTTPResponse
|
||||
rtt: HttpRTT
|
||||
url: String
|
||||
}
|
||||
|
||||
type ICMP {
|
||||
requests: Int
|
||||
rtt: Int
|
||||
}
|
||||
|
||||
type KubernetesContainer {
|
||||
image: String
|
||||
name: String
|
||||
}
|
||||
|
||||
type KubernetesNode {
|
||||
name: String
|
||||
}
|
||||
|
||||
type KubernetesPod {
|
||||
name: String
|
||||
uid: String
|
||||
}
|
||||
|
||||
type Kubernetes {
|
||||
container: KubernetesContainer
|
||||
namespace: String
|
||||
node: KubernetesNode
|
||||
pod: KubernetesPod
|
||||
}
|
||||
|
||||
type MetaCloud {
|
||||
availability_zone: String
|
||||
instance_id: String
|
||||
instance_name: String
|
||||
machine_type: String
|
||||
project_id: String
|
||||
provider: String
|
||||
region: String
|
||||
}
|
||||
|
||||
type Meta {
|
||||
cloud: MetaCloud
|
||||
}
|
||||
|
||||
type Monitor {
|
||||
duration: Duration
|
||||
host: String
|
||||
"The id of the monitor"
|
||||
id: String
|
||||
"The IP pinged by the monitor"
|
||||
ip: String
|
||||
"The name of the protocol being monitored"
|
||||
name: String
|
||||
"The protocol scheme of the monitored host"
|
||||
scheme: String
|
||||
"The status of the monitored host"
|
||||
status: String
|
||||
"The type of host being monitored"
|
||||
type: String
|
||||
check_group: String
|
||||
}
|
||||
|
||||
"Metadata added by a proccessor, which is specified in its configuration."
|
||||
type Observer {
|
||||
"Geolocation data for the agent."
|
||||
geo: Geo
|
||||
}
|
||||
|
||||
type Resolve {
|
||||
host: String
|
||||
ip: String
|
||||
rtt: Duration
|
||||
}
|
||||
|
||||
type RTT {
|
||||
connect: Duration
|
||||
handshake: Duration
|
||||
validate: Duration
|
||||
}
|
||||
|
||||
type Socks5 {
|
||||
rtt: RTT
|
||||
}
|
||||
|
||||
type TCP {
|
||||
port: Int
|
||||
rtt: RTT
|
||||
}
|
||||
|
||||
"Contains monitor transmission encryption information."
|
||||
type PingTLS {
|
||||
"The date and time after which the certificate is invalid."
|
||||
certificate_not_valid_after: String
|
||||
certificate_not_valid_before: String
|
||||
certificates: String
|
||||
rtt: RTT
|
||||
}
|
||||
|
||||
type URL {
|
||||
full: String
|
||||
scheme: String
|
||||
domain: String
|
||||
port: Int
|
||||
path: String
|
||||
query: String
|
||||
}
|
||||
|
||||
"A request sent from a monitor to a host"
|
||||
type Ping {
|
||||
"unique ID for this ping"
|
||||
id: String!
|
||||
"The timestamp of the ping's creation"
|
||||
timestamp: String!
|
||||
"The agent that recorded the ping"
|
||||
beat: Beat
|
||||
container: Container
|
||||
docker: Docker
|
||||
ecs: ECS
|
||||
error: Error
|
||||
host: Host
|
||||
http: HTTP
|
||||
icmp: ICMP
|
||||
kubernetes: Kubernetes
|
||||
meta: Meta
|
||||
monitor: Monitor
|
||||
observer: Observer
|
||||
resolve: Resolve
|
||||
socks5: Socks5
|
||||
summary: Summary
|
||||
tags: String
|
||||
tcp: TCP
|
||||
tls: PingTLS
|
||||
url: URL
|
||||
}
|
||||
`;
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* 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 { RequestHandlerContext, CallAPIOptions, SavedObjectsClient } from 'src/core/server';
|
||||
import { UMServerLibs } from '../lib/lib';
|
||||
|
||||
export type UMContext = RequestHandlerContext & {
|
||||
APICaller: (
|
||||
endpoint: string,
|
||||
clientParams?: Record<string, any>,
|
||||
options?: CallAPIOptions | undefined
|
||||
) => Promise<any>;
|
||||
savedObjectsClient: SavedObjectsClient;
|
||||
};
|
||||
|
||||
export interface UMGraphQLResolver {
|
||||
Query?: any;
|
||||
}
|
||||
|
||||
export type CreateUMGraphQLResolvers = (libs: UMServerLibs) => any;
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* 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 { parseLiteral } from '../resolvers';
|
||||
|
||||
describe('parseLiteral', () => {
|
||||
it('parses string literal of type IntValue', () => {
|
||||
const result = parseLiteral({
|
||||
kind: 'IntValue',
|
||||
value: '1562605032000',
|
||||
});
|
||||
expect(result).toBe(1562605032000);
|
||||
});
|
||||
|
||||
it('parses string literal of type FloatValue', () => {
|
||||
const result = parseLiteral({
|
||||
kind: 'FloatValue',
|
||||
value: '1562605032000.0',
|
||||
});
|
||||
expect(result).toBe(1562605032000);
|
||||
});
|
||||
|
||||
it('parses string literal of type String', () => {
|
||||
const result = parseLiteral({
|
||||
kind: 'StringValue',
|
||||
value: '1562605032000',
|
||||
});
|
||||
expect(result).toBe(1562605032000);
|
||||
});
|
||||
|
||||
it('returns `null` for unsupported types', () => {
|
||||
expect(
|
||||
parseLiteral({
|
||||
kind: 'EnumValue',
|
||||
value: 'false',
|
||||
})
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* 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 { parseValue } from '../resolvers';
|
||||
|
||||
describe('parseValue', () => {
|
||||
it(`parses a number value and returns it if its > 0`, () => {
|
||||
const result = parseValue('1562605032000');
|
||||
expect(result).toBe(1562605032000);
|
||||
});
|
||||
|
||||
it(`parses a number and returns null if its value is < 0`, () => {
|
||||
const result = parseValue('-1562605032000');
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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 { serialize } from '../resolvers';
|
||||
|
||||
describe('serialize', () => {
|
||||
it('serializes date strings correctly', () => {
|
||||
const result = serialize('2019-07-08T16:59:09.796Z');
|
||||
expect(result).toBe(1562605149796);
|
||||
});
|
||||
|
||||
it('serializes timestamp strings correctly', () => {
|
||||
const result = serialize('1562605032000');
|
||||
expect(result).toBe(1562605032000);
|
||||
});
|
||||
|
||||
it('serializes non-date and non-numeric values to NaN', () => {
|
||||
const result = serialize('foo');
|
||||
expect(result).toBeNaN();
|
||||
});
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* 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 { unsignedIntegerResolverFunctions } from './resolvers';
|
||||
export { unsignedIntegerSchema } from './schema.gql';
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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 { GraphQLScalarType, Kind, ValueNode } from 'graphql';
|
||||
import { UMServerLibs } from '../../lib/lib';
|
||||
import { CreateUMGraphQLResolvers } from '../types';
|
||||
|
||||
export const serialize = (value: any): number => {
|
||||
// `parseInt` will yield `2019` for a value such as "2019-07-08T16:59:09.796Z"
|
||||
if (isNaN(Number(value))) {
|
||||
return Date.parse(value);
|
||||
}
|
||||
return parseInt(value, 10);
|
||||
};
|
||||
|
||||
export const parseValue = (value: any) => {
|
||||
const parsed = parseInt(value, 10);
|
||||
if (parsed < 0) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
export const parseLiteral = (ast: ValueNode) => {
|
||||
switch (ast.kind) {
|
||||
case Kind.INT:
|
||||
case Kind.FLOAT:
|
||||
case Kind.STRING:
|
||||
return parseInt(ast.value, 10);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const unsignedIntegerScalar = new GraphQLScalarType({
|
||||
name: 'UnsignedInteger',
|
||||
description: 'Represents an unsigned 32-bit integer',
|
||||
serialize,
|
||||
parseValue,
|
||||
parseLiteral,
|
||||
});
|
||||
|
||||
/**
|
||||
* This scalar resolver will parse an integer string of > 32 bits and return a value of type `number`.
|
||||
* This assumes that the code is running in an environment that supports big ints.
|
||||
*/
|
||||
export const unsignedIntegerResolverFunctions: CreateUMGraphQLResolvers = (libs: UMServerLibs) => ({
|
||||
UnsignedInteger: unsignedIntegerScalar,
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* 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 gql from 'graphql-tag';
|
||||
|
||||
export const unsignedIntegerSchema = gql`
|
||||
scalar UnsignedInteger
|
||||
`;
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { GraphQLSchema } from 'graphql';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import {
|
||||
IRouter,
|
||||
|
@ -44,5 +43,4 @@ export interface UptimeCorePlugins {
|
|||
|
||||
export interface UMBackendFrameworkAdapter {
|
||||
registerRoute(route: UMKibanaRoute): void;
|
||||
registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { GraphQLSchema } from 'graphql';
|
||||
import { schema as kbnSchema } from '@kbn/config-schema';
|
||||
import { runHttpQuery } from 'apollo-server-core';
|
||||
import { UptimeCoreSetup } from './adapter_types';
|
||||
import { UMBackendFrameworkAdapter } from './adapter_types';
|
||||
import { UMKibanaRoute } from '../../../rest_api';
|
||||
|
@ -33,71 +30,4 @@ export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapte
|
|||
throw new Error(`Handler for method ${method} is not defined`);
|
||||
}
|
||||
}
|
||||
|
||||
public registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void {
|
||||
this.server.route.post(
|
||||
{
|
||||
path: routePath,
|
||||
validate: {
|
||||
body: kbnSchema.object({
|
||||
operationName: kbnSchema.nullable(kbnSchema.string()),
|
||||
query: kbnSchema.string(),
|
||||
variables: kbnSchema.recordOf(kbnSchema.string(), kbnSchema.any()),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:uptime-read'],
|
||||
},
|
||||
},
|
||||
async (context, request, resp): Promise<any> => {
|
||||
const {
|
||||
core: {
|
||||
elasticsearch: {
|
||||
dataClient: { callAsCurrentUser },
|
||||
},
|
||||
},
|
||||
} = context;
|
||||
const options = {
|
||||
graphQLOptions: (_req: any) => {
|
||||
return {
|
||||
context: {
|
||||
...context,
|
||||
APICaller: callAsCurrentUser,
|
||||
savedObjectsClient: context.core.savedObjects.client,
|
||||
},
|
||||
schema,
|
||||
};
|
||||
},
|
||||
path: routePath,
|
||||
route: {
|
||||
tags: ['access:uptime-read'],
|
||||
},
|
||||
};
|
||||
try {
|
||||
const query = request.body as Record<string, any>;
|
||||
|
||||
const graphQLResponse = await runHttpQuery([request], {
|
||||
method: 'POST',
|
||||
options: options.graphQLOptions,
|
||||
query,
|
||||
});
|
||||
|
||||
return resp.ok({
|
||||
body: graphQLResponse,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.isGraphQLError === true) {
|
||||
return resp.internalError({
|
||||
body: { message: error.message },
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
}
|
||||
return resp.internalError();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,11 +68,11 @@ export const getMonitorDetails: UMElasticsearchQueryFn<
|
|||
const data = result.hits.hits[0]?._source;
|
||||
|
||||
const monitorError: MonitorError | undefined = data?.error;
|
||||
const errorTimeStamp: string | undefined = data?.['@timestamp'];
|
||||
const errorTimestamp: string | undefined = data?.['@timestamp'];
|
||||
|
||||
return {
|
||||
monitorId,
|
||||
error: monitorError,
|
||||
timestamp: errorTimeStamp,
|
||||
timestamp: errorTimestamp,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,10 +8,11 @@ import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/co
|
|||
import { fetchPage } from './search';
|
||||
import { UMElasticsearchQueryFn } from '../adapters';
|
||||
import {
|
||||
MonitorSummary,
|
||||
SortOrder,
|
||||
CursorDirection,
|
||||
} from '../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
MonitorSummary,
|
||||
} from '../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
|
||||
import { QueryContext } from './search';
|
||||
|
||||
export interface CursorPagination {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
MonitorGroupsPage,
|
||||
} from '../fetch_page';
|
||||
import { QueryContext } from '../query_context';
|
||||
import { MonitorSummary } from '../../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
import { MonitorSummary } from '../../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { nextPagination, prevPagination, simpleQueryContext } from './test_helpers';
|
||||
|
||||
const simpleFixture: MonitorGroups[] = [
|
||||
|
@ -53,12 +53,16 @@ const simpleFetcher = (monitorGroups: MonitorGroups[]): MonitorGroupsFetcher =>
|
|||
};
|
||||
|
||||
const simpleEnricher = (monitorGroups: MonitorGroups[]): MonitorEnricher => {
|
||||
return async (queryContext: QueryContext, checkGroups: string[]): Promise<MonitorSummary[]> => {
|
||||
return async (_queryContext: QueryContext, checkGroups: string[]): Promise<MonitorSummary[]> => {
|
||||
return checkGroups.map(cg => {
|
||||
const monitorGroup = monitorGroups.find(mg => mg.groups.some(g => g.checkGroup === cg))!;
|
||||
return {
|
||||
monitor_id: monitorGroup.id,
|
||||
state: { summary: {}, timestamp: new Date(Date.parse('1999-12-31')).toISOString() },
|
||||
state: {
|
||||
summary: {},
|
||||
timestamp: new Date(Date.parse('1999-12-31')).valueOf().toString(),
|
||||
url: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
@ -71,16 +75,37 @@ describe('fetching a page', () => {
|
|||
simpleFetcher(simpleFixture),
|
||||
simpleEnricher(simpleFixture)
|
||||
);
|
||||
expect(res).toEqual({
|
||||
items: [
|
||||
{
|
||||
monitor_id: 'foo',
|
||||
state: { summary: {}, timestamp: '1999-12-31T00:00:00.000Z' },
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"monitor_id": "foo",
|
||||
"state": Object {
|
||||
"summary": Object {},
|
||||
"timestamp": "946598400000",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"monitor_id": "bar",
|
||||
"state": Object {
|
||||
"summary": Object {},
|
||||
"timestamp": "946598400000",
|
||||
"url": Object {},
|
||||
},
|
||||
},
|
||||
],
|
||||
"nextPagePagination": Object {
|
||||
"cursorDirection": "AFTER",
|
||||
"cursorKey": "bar",
|
||||
"sortOrder": "ASC",
|
||||
},
|
||||
{ monitor_id: 'bar', state: { summary: {}, timestamp: '1999-12-31T00:00:00.000Z' } },
|
||||
],
|
||||
nextPagePagination: { cursorDirection: 'AFTER', sortOrder: 'ASC', cursorKey: 'bar' },
|
||||
prevPagePagination: { cursorDirection: 'BEFORE', sortOrder: 'ASC', cursorKey: 'foo' },
|
||||
});
|
||||
"prevPagePagination": Object {
|
||||
"cursorDirection": "BEFORE",
|
||||
"cursorKey": "foo",
|
||||
"sortOrder": "ASC",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { CursorPagination } from '../types';
|
|||
import {
|
||||
CursorDirection,
|
||||
SortOrder,
|
||||
} from '../../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
} from '../../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
|
||||
describe(QueryContext, () => {
|
||||
// 10 minute range
|
||||
|
|
|
@ -8,7 +8,7 @@ import { CursorPagination } from '../types';
|
|||
import {
|
||||
CursorDirection,
|
||||
SortOrder,
|
||||
} from '../../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
} from '../../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { QueryContext } from '../query_context';
|
||||
|
||||
export const prevPagination = (key: any): CursorPagination => {
|
||||
|
|
|
@ -8,12 +8,12 @@ import { get, sortBy } from 'lodash';
|
|||
import { QueryContext } from './query_context';
|
||||
import { QUERY, STATES } from '../../../../../../legacy/plugins/uptime/common/constants';
|
||||
import {
|
||||
MonitorSummary,
|
||||
SummaryHistogram,
|
||||
Check,
|
||||
Histogram,
|
||||
MonitorSummary,
|
||||
CursorDirection,
|
||||
SortOrder,
|
||||
} from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
} from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { MonitorEnricher } from './fetch_page';
|
||||
|
||||
export const enrichMonitorGroups: MonitorEnricher = async (
|
||||
|
@ -250,11 +250,8 @@ export const enrichMonitorGroups: MonitorEnricher = async (
|
|||
const summaries: MonitorSummary[] = monitorBuckets.map((monitor: any) => {
|
||||
const monitorId = get<string>(monitor, 'key.monitor_id');
|
||||
monitorIds.push(monitorId);
|
||||
let state = get<any>(monitor, 'state.value');
|
||||
state = {
|
||||
...state,
|
||||
timestamp: state['@timestamp'],
|
||||
};
|
||||
const state: any = monitor.state?.value;
|
||||
state.timestamp = state['@timestamp'];
|
||||
const { checks } = state;
|
||||
if (checks) {
|
||||
state.checks = sortBy<SortChecks, Check>(checks, checksSortBy);
|
||||
|
@ -289,7 +286,7 @@ export const enrichMonitorGroups: MonitorEnricher = async (
|
|||
const getHistogramForMonitors = async (
|
||||
queryContext: QueryContext,
|
||||
monitorIds: string[]
|
||||
): Promise<{ [key: string]: SummaryHistogram }> => {
|
||||
): Promise<{ [key: string]: Histogram }> => {
|
||||
const params = {
|
||||
index: queryContext.heartbeatIndices,
|
||||
body: {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
CursorDirection,
|
||||
MonitorSummary,
|
||||
SortOrder,
|
||||
} from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
} from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { enrichMonitorGroups } from './enrich_monitor_groups';
|
||||
import { MonitorGroupIterator } from './monitor_group_iterator';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { get, set } from 'lodash';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { QueryContext } from './query_context';
|
||||
|
||||
// This is the first phase of the query. In it, we find the most recent check groups that matched the given query.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { QueryContext } from './query_context';
|
||||
import { fetchChunk } from './fetch_chunk';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { MonitorGroups } from './fetch_page';
|
||||
import { CursorPagination } from './types';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { QueryContext } from './query_context';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
import { MonitorGroups, MonitorLocCheckGroup } from './fetch_page';
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import {
|
||||
CursorDirection,
|
||||
SortOrder,
|
||||
} from '../../../../../../legacy/plugins/uptime/common/graphql/types';
|
||||
} from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
|
||||
export interface CursorPagination {
|
||||
cursorKey?: any;
|
||||
|
|
|
@ -12,6 +12,7 @@ import { createGetSnapshotCount } from './snapshot';
|
|||
import { UMRestApiRouteFactory } from './types';
|
||||
import {
|
||||
createGetMonitorDetailsRoute,
|
||||
createMonitorListRoute,
|
||||
createGetMonitorLocationsRoute,
|
||||
createGetStatusBarRoute,
|
||||
} from './monitors';
|
||||
|
@ -30,6 +31,7 @@ export const restApiRoutes: UMRestApiRouteFactory[] = [
|
|||
createPostDynamicSettingsRoute,
|
||||
createGetMonitorDetailsRoute,
|
||||
createGetMonitorLocationsRoute,
|
||||
createMonitorListRoute,
|
||||
createGetStatusBarRoute,
|
||||
createGetSnapshotCount,
|
||||
createLogPageViewRoute,
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
*/
|
||||
|
||||
export { createGetMonitorDetailsRoute } from './monitors_details';
|
||||
export { createMonitorListRoute } from './monitor_list';
|
||||
export { createGetMonitorLocationsRoute } from './monitor_locations';
|
||||
export { createGetStatusBarRoute } from './monitor_status';
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 { schema } from '@kbn/config-schema';
|
||||
import { UMRestApiRouteFactory } from '../types';
|
||||
import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants';
|
||||
import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api';
|
||||
|
||||
export const createMonitorListRoute: UMRestApiRouteFactory = libs => ({
|
||||
method: 'GET',
|
||||
path: API_URLS.MONITOR_LIST,
|
||||
validate: {
|
||||
query: schema.object({
|
||||
dateRangeStart: schema.string(),
|
||||
dateRangeEnd: schema.string(),
|
||||
filters: schema.maybe(schema.string()),
|
||||
pagination: schema.maybe(schema.string()),
|
||||
statusFilter: schema.maybe(schema.string()),
|
||||
pageSize: schema.number(),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:uptime-read'],
|
||||
},
|
||||
handler: async ({ callES, dynamicSettings }, _context, request, response): Promise<any> => {
|
||||
const {
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
filters,
|
||||
pagination,
|
||||
statusFilter,
|
||||
pageSize,
|
||||
} = request.query;
|
||||
|
||||
const decodedPagination = pagination
|
||||
? JSON.parse(decodeURIComponent(pagination))
|
||||
: CONTEXT_DEFAULTS.CURSOR_PAGINATION;
|
||||
const [indexStatus, { summaries, nextPagePagination, prevPagePagination }] = await Promise.all([
|
||||
libs.requests.getIndexStatus({ callES, dynamicSettings }),
|
||||
libs.requests.getMonitorStates({
|
||||
callES,
|
||||
dynamicSettings,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
pagination: decodedPagination,
|
||||
pageSize,
|
||||
filters,
|
||||
// this is added to make typescript happy,
|
||||
// this sort of reassignment used to be further downstream but I've moved it here
|
||||
// because this code is going to be decomissioned soon
|
||||
statusFilter: statusFilter || undefined,
|
||||
}),
|
||||
]);
|
||||
|
||||
const totalSummaryCount = indexStatus?.docCount ?? 0;
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
summaries,
|
||||
nextPagePagination,
|
||||
prevPagePagination,
|
||||
totalSummaryCount,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
|
@ -4,8 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { makeExecutableSchema } from 'graphql-tools';
|
||||
import { DEFAULT_GRAPHQL_PATH, resolvers, typeDefs } from './graphql';
|
||||
import { UMServerLibs } from './lib/lib';
|
||||
import { createRouteWithAuth, restApiRoutes, uptimeRouteWrapper } from './rest_api';
|
||||
import { UptimeCoreSetup, UptimeCorePlugins } from './lib/adapters';
|
||||
|
@ -23,10 +21,4 @@ export const initUptimeServer = (
|
|||
uptimeAlertTypeFactories.forEach(alertTypeFactory =>
|
||||
plugins.alerting.registerType(alertTypeFactory(server, libs))
|
||||
);
|
||||
|
||||
const graphQLSchema = makeExecutableSchema({
|
||||
resolvers: resolvers.map(createResolversFn => createResolversFn(libs)),
|
||||
typeDefs,
|
||||
});
|
||||
libs.framework.registerGraphQLEndpoint(DEFAULT_GRAPHQL_PATH, graphQLSchema);
|
||||
};
|
||||
|
|
|
@ -26,17 +26,6 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
expect(result.response).to.have.property('statusCode', 200);
|
||||
};
|
||||
|
||||
const executeRESTAPIQuery = async (username: string, password: string, spaceId?: string) => {
|
||||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||
|
||||
return await supertest
|
||||
.get(basePath + API_URLS.INDEX_STATUS)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.then((response: any) => ({ error: undefined, response }))
|
||||
.catch((error: any) => ({ error, response: undefined }));
|
||||
};
|
||||
|
||||
const executePingsRequest = async (username: string, password: string, spaceId?: string) => {
|
||||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||
|
||||
|
@ -72,9 +61,6 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
full_name: 'a kibana user',
|
||||
});
|
||||
|
||||
const graphQLResult = await executeRESTAPIQuery(username, password);
|
||||
expect404(graphQLResult);
|
||||
|
||||
const pingsResult = await executePingsRequest(username, password);
|
||||
expect404(pingsResult);
|
||||
} finally {
|
||||
|
@ -111,9 +97,6 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
full_name: 'a kibana user',
|
||||
});
|
||||
|
||||
const graphQLResult = await executeRESTAPIQuery(username, password);
|
||||
expectResponse(graphQLResult);
|
||||
|
||||
const pingsResult = await executePingsRequest(username, password);
|
||||
expectResponse(pingsResult);
|
||||
} finally {
|
||||
|
@ -153,9 +136,6 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
full_name: 'a kibana user',
|
||||
});
|
||||
|
||||
const graphQLResult = await executeRESTAPIQuery(username, password);
|
||||
expect404(graphQLResult);
|
||||
|
||||
const pingsResult = await executePingsRequest(username, password);
|
||||
expect404(pingsResult);
|
||||
} finally {
|
||||
|
@ -222,17 +202,11 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
});
|
||||
|
||||
it('user_1 can access APIs in space_1', async () => {
|
||||
const graphQLResult = await executeRESTAPIQuery(username, password, space1Id);
|
||||
expectResponse(graphQLResult);
|
||||
|
||||
const pingsResult = await executePingsRequest(username, password, space1Id);
|
||||
expectResponse(pingsResult);
|
||||
});
|
||||
|
||||
it(`user_1 can't access APIs in space_2`, async () => {
|
||||
const graphQLResult = await executeRESTAPIQuery(username, password);
|
||||
expect404(graphQLResult);
|
||||
|
||||
const pingsResult = await executePingsRequest(username, password);
|
||||
expect404(pingsResult);
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue