mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
chore(rca): Add notes related APIs (#190362)
This commit is contained in:
parent
19e9bfb26e
commit
47c41c16c9
55 changed files with 587 additions and 258 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -513,6 +513,7 @@ test/interactive_setup_api_integration/plugins/test_endpoints @elastic/kibana-se
|
|||
packages/kbn-interpreter @elastic/kibana-visualizations
|
||||
x-pack/plugins/observability_solution/investigate_app @elastic/obs-ux-management-team
|
||||
x-pack/plugins/observability_solution/investigate @elastic/obs-ux-management-team
|
||||
packages/kbn-investigation-shared @elastic/obs-ux-management-team
|
||||
packages/kbn-io-ts-utils @elastic/obs-knowledge-team
|
||||
packages/kbn-ipynb @elastic/search-kibana
|
||||
packages/kbn-jest-serializers @elastic/kibana-operations
|
||||
|
|
|
@ -556,6 +556,7 @@
|
|||
"@kbn/interpreter": "link:packages/kbn-interpreter",
|
||||
"@kbn/investigate-app-plugin": "link:x-pack/plugins/observability_solution/investigate_app",
|
||||
"@kbn/investigate-plugin": "link:x-pack/plugins/observability_solution/investigate",
|
||||
"@kbn/investigation-shared": "link:packages/kbn-investigation-shared",
|
||||
"@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils",
|
||||
"@kbn/ipynb": "link:packages/kbn-ipynb",
|
||||
"@kbn/json-schemas": "link:x-pack/packages/ml/json_schemas",
|
||||
|
|
3
packages/kbn-investigation-shared/README.md
Normal file
3
packages/kbn-investigation-shared/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/investigation-shared
|
||||
|
||||
Empty package generated by @kbn/generate
|
23
packages/kbn-investigation-shared/index.ts
Normal file
23
packages/kbn-investigation-shared/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type * from './src/schema/create';
|
||||
export type * from './src/schema/create_notes';
|
||||
export type * from './src/schema/delete';
|
||||
export type * from './src/schema/find';
|
||||
export type * from './src/schema/get';
|
||||
export type * from './src/schema/get_notes';
|
||||
export type * from './src/schema/origin';
|
||||
|
||||
export * from './src/schema/create';
|
||||
export * from './src/schema/create_notes';
|
||||
export * from './src/schema/delete';
|
||||
export * from './src/schema/find';
|
||||
export * from './src/schema/get';
|
||||
export * from './src/schema/get_notes';
|
||||
export * from './src/schema/origin';
|
13
packages/kbn-investigation-shared/jest.config.js
Normal file
13
packages/kbn-investigation-shared/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-investigation-shared'],
|
||||
};
|
5
packages/kbn-investigation-shared/kibana.jsonc
Normal file
5
packages/kbn-investigation-shared/kibana.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/investigation-shared",
|
||||
"owner": "@elastic/obs-ux-management-team"
|
||||
}
|
6
packages/kbn-investigation-shared/package.json
Normal file
6
packages/kbn-investigation-shared/package.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "@kbn/investigation-shared",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { investigationResponseSchema } from './investigation';
|
||||
import { alertOriginSchema, blankOriginSchema } from './origin';
|
36
packages/kbn-investigation-shared/src/schema/create_notes.ts
Normal file
36
packages/kbn-investigation-shared/src/schema/create_notes.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { investigationNoteResponseSchema } from './investigation_note';
|
||||
|
||||
const createInvestigationNoteParamsSchema = t.type({
|
||||
path: t.type({
|
||||
id: t.string,
|
||||
}),
|
||||
body: t.type({
|
||||
content: t.string,
|
||||
}),
|
||||
});
|
||||
|
||||
const createInvestigationNoteResponseSchema = investigationNoteResponseSchema;
|
||||
|
||||
type CreateInvestigationNoteInput = t.OutputOf<
|
||||
typeof createInvestigationNoteParamsSchema.props.body
|
||||
>;
|
||||
type CreateInvestigationNoteParams = t.TypeOf<
|
||||
typeof createInvestigationNoteParamsSchema.props.body
|
||||
>;
|
||||
type CreateInvestigationNoteResponse = t.OutputOf<typeof createInvestigationNoteResponseSchema>;
|
||||
|
||||
export { createInvestigationNoteParamsSchema, createInvestigationNoteResponseSchema };
|
||||
export type {
|
||||
CreateInvestigationNoteInput,
|
||||
CreateInvestigationNoteParams,
|
||||
CreateInvestigationNoteResponse,
|
||||
};
|
20
packages/kbn-investigation-shared/src/schema/delete.ts
Normal file
20
packages/kbn-investigation-shared/src/schema/delete.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
const deleteInvestigationParamsSchema = t.type({
|
||||
path: t.type({
|
||||
id: t.string,
|
||||
}),
|
||||
});
|
||||
|
||||
type DeleteInvestigationParams = t.TypeOf<typeof deleteInvestigationParamsSchema.props.path>; // Parsed payload used by the backend
|
||||
|
||||
export { deleteInvestigationParamsSchema };
|
||||
export type { DeleteInvestigationParams };
|
|
@ -1,9 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { investigationResponseSchema } from './investigation';
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { investigationResponseSchema } from './investigation';
|
||||
|
23
packages/kbn-investigation-shared/src/schema/get_notes.ts
Normal file
23
packages/kbn-investigation-shared/src/schema/get_notes.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { investigationNoteResponseSchema } from './investigation_note';
|
||||
|
||||
const getInvestigationNotesParamsSchema = t.type({
|
||||
path: t.type({
|
||||
id: t.string,
|
||||
}),
|
||||
});
|
||||
|
||||
const getInvestigationNotesResponseSchema = t.array(investigationNoteResponseSchema);
|
||||
|
||||
type GetInvestigationNotesResponse = t.OutputOf<typeof getInvestigationNotesResponseSchema>;
|
||||
|
||||
export { getInvestigationNotesParamsSchema, getInvestigationNotesResponseSchema };
|
||||
export type { GetInvestigationNotesResponse };
|
|
@ -1,11 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { alertOriginSchema, blankOriginSchema } from './origin';
|
||||
import { investigationNoteResponseSchema } from './investigation_note';
|
||||
|
||||
const investigationResponseSchema = t.type({
|
||||
id: t.string,
|
||||
|
@ -17,6 +20,7 @@ const investigationResponseSchema = t.type({
|
|||
}),
|
||||
origin: t.union([alertOriginSchema, blankOriginSchema]),
|
||||
status: t.union([t.literal('ongoing'), t.literal('closed')]),
|
||||
notes: t.array(investigationNoteResponseSchema),
|
||||
});
|
||||
|
||||
type InvestigationResponse = t.OutputOf<typeof investigationResponseSchema>;
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
const investigationNoteResponseSchema = t.type({
|
||||
id: t.string,
|
||||
content: t.string,
|
||||
createdAt: t.number,
|
||||
createdBy: t.string,
|
||||
});
|
||||
|
||||
type InvestigationNoteResponse = t.OutputOf<typeof investigationNoteResponseSchema>;
|
||||
|
||||
export { investigationNoteResponseSchema };
|
||||
export type { InvestigationNoteResponse };
|
|
@ -1,17 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
const blankOriginSchema = t.type({ type: t.literal('blank') });
|
||||
const alertOriginSchema = t.type({ type: t.literal('alert'), id: t.string });
|
||||
|
||||
type AlertOrigin = t.OutputOf<typeof alertOriginSchema>;
|
||||
type BlankOrigin = t.OutputOf<typeof blankOriginSchema>;
|
||||
|
||||
export { alertOriginSchema, blankOriginSchema };
|
||||
|
||||
export type { AlertOrigin, BlankOrigin };
|
17
packages/kbn-investigation-shared/tsconfig.json
Normal file
17
packages/kbn-investigation-shared/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
],
|
||||
"kbn_references": []
|
||||
}
|
|
@ -1020,6 +1020,8 @@
|
|||
"@kbn/investigate-app-plugin/*": ["x-pack/plugins/observability_solution/investigate_app/*"],
|
||||
"@kbn/investigate-plugin": ["x-pack/plugins/observability_solution/investigate"],
|
||||
"@kbn/investigate-plugin/*": ["x-pack/plugins/observability_solution/investigate/*"],
|
||||
"@kbn/investigation-shared": ["packages/kbn-investigation-shared"],
|
||||
"@kbn/investigation-shared/*": ["packages/kbn-investigation-shared/*"],
|
||||
"@kbn/io-ts-utils": ["packages/kbn-io-ts-utils"],
|
||||
"@kbn/io-ts-utils/*": ["packages/kbn-io-ts-utils/*"],
|
||||
"@kbn/ipynb": ["packages/kbn-ipynb"],
|
||||
|
|
|
@ -14,11 +14,3 @@ export type {
|
|||
export { mergePlainObjects } from './utils/merge_plain_objects';
|
||||
|
||||
export { InvestigateWidgetColumnSpan } from './types';
|
||||
|
||||
export type { CreateInvestigationInput, CreateInvestigationResponse } from './schema/create';
|
||||
export type { GetInvestigationParams } from './schema/get';
|
||||
export type { FindInvestigationsResponse } from './schema/find';
|
||||
|
||||
export { createInvestigationParamsSchema } from './schema/create';
|
||||
export { getInvestigationParamsSchema } from './schema/get';
|
||||
export { findInvestigationsParamsSchema } from './schema/find';
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface Investigation {
|
|||
export interface InvestigationNote {
|
||||
id: string;
|
||||
createdAt: number;
|
||||
createdBy: AuthenticatedUser;
|
||||
createdBy: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { useContext, createContext } from 'react';
|
||||
import { createContext } from 'react';
|
||||
import type { InvestigateWidgetCreate } from '../../common';
|
||||
|
||||
export interface UseInvestigateWidgetApi<
|
||||
|
@ -17,9 +17,3 @@ export interface UseInvestigateWidgetApi<
|
|||
const InvestigateWidgetApiContext = createContext<UseInvestigateWidgetApi | undefined>(undefined);
|
||||
|
||||
export const InvestigateWidgetApiContextProvider = InvestigateWidgetApiContext.Provider;
|
||||
|
||||
export function useInvestigateWidget(): UseInvestigateWidgetApi | undefined {
|
||||
const context = useContext(InvestigateWidgetApiContext);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ export function createInvestigationStore({
|
|||
notes: prevInvestigation.notes.concat({
|
||||
id: v4(),
|
||||
createdAt: Date.now(),
|
||||
createdBy: user,
|
||||
createdBy: user.username,
|
||||
content: note,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { CoreSetup, CoreStart, PluginInitializerContext, Plugin } from '@kbn/core/public';
|
||||
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import { useMemo } from 'react';
|
||||
import { useInvestigateWidget } from './hooks/use_investigate_widget';
|
||||
import { createUseInvestigation } from './hooks/use_investigation';
|
||||
import type {
|
||||
ConfigSchema,
|
||||
|
@ -73,7 +72,6 @@ export class InvestigatePlugin
|
|||
to,
|
||||
});
|
||||
},
|
||||
useInvestigateWidget,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface*/
|
||||
import type { FromSchema } from 'json-schema-to-ts';
|
||||
import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { AuthenticatedUser } from '@kbn/core/public';
|
||||
import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { FromSchema } from 'json-schema-to-ts';
|
||||
import type { InvestigateWidget } from '../common';
|
||||
import type { GlobalWidgetParameters, InvestigateWidgetCreate } from '../common/types';
|
||||
import type { UseInvestigationApi } from './hooks/use_investigation';
|
||||
import type { UseInvestigateWidgetApi } from './hooks/use_investigate_widget';
|
||||
|
||||
export enum ChromeOption {
|
||||
disabled = 'disabled',
|
||||
|
@ -84,5 +83,4 @@ export interface InvestigatePublicStart {
|
|||
from: string;
|
||||
to: string;
|
||||
}) => UseInvestigationApi;
|
||||
useInvestigateWidget: () => UseInvestigateWidgetApi | undefined;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
"public/**/*",
|
||||
"typings/**/*",
|
||||
"public/**/*.json",
|
||||
"server/**/*"
|
||||
],
|
||||
"server/**/*", ],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/logging",
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
import type { CoreStart, CoreTheme } from '@kbn/core/public';
|
||||
import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme';
|
||||
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
|
||||
import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config';
|
||||
import { Route, Router, Routes } from '@kbn/shared-ux-router';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import type { History } from 'history';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { Observable } from 'rxjs';
|
||||
import { InvestigateAppContextProvider } from './components/investigate_app_context_provider';
|
||||
import { InvestigateAppKibanaContext } from './hooks/use_kibana';
|
||||
import { investigateRouter } from './routes/config';
|
||||
import { getRoutes } from './routes/config';
|
||||
import { InvestigateAppServices } from './services/types';
|
||||
import type { InvestigateAppStartDependencies } from './types';
|
||||
|
||||
|
@ -46,6 +46,21 @@ function Application({
|
|||
[coreStart, pluginsStart, services]
|
||||
);
|
||||
|
||||
const App = () => {
|
||||
const routes = getRoutes();
|
||||
return (
|
||||
<Routes>
|
||||
{Object.keys(routes).map((path) => {
|
||||
const { handler, exact } = routes[path];
|
||||
const Wrapper = () => {
|
||||
return handler();
|
||||
};
|
||||
return <Route key={path} path={path} exact={exact} component={Wrapper} />;
|
||||
})}
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
return (
|
||||
|
@ -53,11 +68,11 @@ function Application({
|
|||
<InvestigateAppContextProvider context={context}>
|
||||
<RedirectAppLinks coreStart={coreStart}>
|
||||
<coreStart.i18n.Context>
|
||||
<RouterProvider history={history} router={investigateRouter as any}>
|
||||
<Router history={history}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<RouteRenderer />
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
</RouterProvider>
|
||||
</Router>
|
||||
</coreStart.i18n.Context>
|
||||
</RedirectAppLinks>
|
||||
</InvestigateAppContextProvider>
|
||||
|
|
|
@ -1,21 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export function useAbortSignal() {
|
||||
const controllerRef = useRef(new AbortController());
|
||||
|
||||
useEffect(() => {
|
||||
const controller = controllerRef.current;
|
||||
return () => {
|
||||
controller.abort();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return controllerRef.current.signal;
|
||||
}
|
|
@ -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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import {
|
||||
CreateInvestigationNoteInput,
|
||||
CreateInvestigationNoteResponse,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
type ServerError = IHttpFetchError<ResponseErrorBody>;
|
||||
|
||||
export function useAddInvestigationNote() {
|
||||
const {
|
||||
core: {
|
||||
http,
|
||||
notifications: { toasts },
|
||||
},
|
||||
} = useKibana();
|
||||
|
||||
return useMutation<
|
||||
CreateInvestigationNoteResponse,
|
||||
ServerError,
|
||||
{ investigationId: string; note: CreateInvestigationNoteInput },
|
||||
{ investigationId: string }
|
||||
>(
|
||||
['addInvestigationNote'],
|
||||
({ investigationId, note }) => {
|
||||
const body = JSON.stringify(note);
|
||||
return http.post<CreateInvestigationNoteResponse>(
|
||||
`/api/observability/investigations/${investigationId}/notes`,
|
||||
{ body, version: '2023-10-31' }
|
||||
);
|
||||
},
|
||||
{
|
||||
onSuccess: (response, {}) => {
|
||||
// TODO: clear investigationNotes key from queryClient, and push new note to the internal store.
|
||||
// console.log(response);
|
||||
toasts.addSuccess('Note saved');
|
||||
},
|
||||
onError: (error, {}, context) => {
|
||||
// console.log(error);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { GetInvestigationResponse } from '@kbn/investigation-shared';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { investigationKeys } from './query_key_factory';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
export interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface UseFetchInvestigationResponse {
|
||||
isInitialLoading: boolean;
|
||||
isLoading: boolean;
|
||||
isRefetching: boolean;
|
||||
isSuccess: boolean;
|
||||
isError: boolean;
|
||||
data: GetInvestigationResponse | undefined;
|
||||
}
|
||||
|
||||
export function useFetchInvestigation({ id }: Params): UseFetchInvestigationResponse {
|
||||
const {
|
||||
core: {
|
||||
http,
|
||||
notifications: { toasts },
|
||||
},
|
||||
} = useKibana();
|
||||
|
||||
const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
|
||||
queryKey: investigationKeys.fetch({ id }),
|
||||
queryFn: async ({ signal }) => {
|
||||
return await http.get<GetInvestigationResponse>(`/api/observability/investigations/${id}`, {
|
||||
version: '2023-10-31',
|
||||
signal,
|
||||
});
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
onError: (error: Error) => {
|
||||
toasts.addError(error, {
|
||||
title: 'Something went wrong while fetching Investigations',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
isInitialLoading,
|
||||
isLoading,
|
||||
isRefetching,
|
||||
isSuccess,
|
||||
isError,
|
||||
};
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common';
|
||||
import { FindInvestigationsResponse } from '@kbn/investigation-shared';
|
||||
import { investigationKeys } from './query_key_factory';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { BASE_RAC_ALERTS_API_PATH, EcsFieldsResponse } from '@kbn/rule-registry-
|
|||
import { useKibana } from './use_kibana';
|
||||
|
||||
export interface AlertParams {
|
||||
id: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface UseFetchAlertResponse {
|
||||
|
@ -40,15 +40,7 @@ export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse {
|
|||
signal,
|
||||
});
|
||||
},
|
||||
cacheTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: (failureCount, error) => {
|
||||
if (String(error) === 'Error: Forbidden') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return failureCount < 3;
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toasts.addError(error, {
|
||||
title: 'Something went wrong while fetching alert',
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/get';
|
||||
import { GetInvestigationResponse } from '@kbn/investigation-shared';
|
||||
import { investigationKeys } from './query_key_factory';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
|
@ -41,15 +41,7 @@ export function useFetchInvestigation({
|
|||
signal,
|
||||
});
|
||||
},
|
||||
cacheTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: (failureCount, error) => {
|
||||
if (String(error) === 'Error: Forbidden') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return failureCount < 3;
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toasts.addError(error, {
|
||||
title: 'Something went wrong while fetching Investigation',
|
||||
|
|
|
@ -1,14 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { type PathsOf, type TypeOf, useParams } from '@kbn/typed-react-router-config';
|
||||
import type { InvestigateRoutes } from '../routes/config';
|
||||
|
||||
export function useInvestigateParams<TPath extends PathsOf<InvestigateRoutes>>(
|
||||
path: TPath
|
||||
): TypeOf<InvestigateRoutes, TPath> {
|
||||
return useParams(path)! as TypeOf<InvestigateRoutes, TPath>;
|
||||
}
|
|
@ -1,55 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { PathsOf, TypeAsArgs, TypeOf } from '@kbn/typed-react-router-config';
|
||||
import { useMemo } from 'react';
|
||||
import { InvestigateRouter, InvestigateRoutes } from '../routes/config';
|
||||
import { investigateRouter } from '../routes/config';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
interface StatefulInvestigateRouter extends InvestigateRouter {
|
||||
push<T extends PathsOf<InvestigateRoutes>>(
|
||||
path: T,
|
||||
...params: TypeAsArgs<TypeOf<InvestigateRoutes, T>>
|
||||
): void;
|
||||
replace<T extends PathsOf<InvestigateRoutes>>(
|
||||
path: T,
|
||||
...params: TypeAsArgs<TypeOf<InvestigateRoutes, T>>
|
||||
): void;
|
||||
}
|
||||
|
||||
export function useInvestigateRouter(): StatefulInvestigateRouter {
|
||||
const {
|
||||
core: {
|
||||
http,
|
||||
application: { navigateToApp },
|
||||
},
|
||||
} = useKibana();
|
||||
|
||||
const link = (...args: any[]) => {
|
||||
// @ts-expect-error
|
||||
return investigateRouter.link(...args);
|
||||
};
|
||||
|
||||
return useMemo<StatefulInvestigateRouter>(
|
||||
() => ({
|
||||
...investigateRouter,
|
||||
push: (...args) => {
|
||||
const next = link(...args);
|
||||
navigateToApp('investigations', { path: next, replace: false });
|
||||
},
|
||||
replace: (path, ...args) => {
|
||||
const next = link(path, ...args);
|
||||
navigateToApp('investigations', { path: next, replace: true });
|
||||
},
|
||||
link: (path, ...args) => {
|
||||
return http.basePath.prepend('/app/investigations' + link(path, ...args));
|
||||
},
|
||||
}),
|
||||
[navigateToApp, http.basePath]
|
||||
);
|
||||
}
|
|
@ -20,7 +20,7 @@ export default meta;
|
|||
|
||||
const defaultProps: ComponentStoryObj<typeof Component> = {
|
||||
args: {},
|
||||
render: (props) => <Component {...props} />,
|
||||
render: (props) => <Component investigationId="123" />,
|
||||
};
|
||||
|
||||
export const InvestigateViewStory: ComponentStoryObj<typeof Component> = {
|
||||
|
|
|
@ -6,27 +6,41 @@
|
|||
*/
|
||||
import datemath from '@elastic/datemath';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import type { InvestigateWidgetCreate } from '@kbn/investigate-plugin/public';
|
||||
import { AuthenticatedUser } from '@kbn/security-plugin/common';
|
||||
import { keyBy, noop } from 'lodash';
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { AddObservationUI } from '../../../../components/add_observation_ui';
|
||||
import { InvestigateSearchBar } from '../../../../components/investigate_search_bar';
|
||||
import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid';
|
||||
import { useAddInvestigationNote } from '../../../../hooks/use_add_investigation_note';
|
||||
import { useDateRange } from '../../../../hooks/use_date_range';
|
||||
import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation';
|
||||
import { useKibana } from '../../../../hooks/use_kibana';
|
||||
import { InvestigationNotes } from '../investigation_notes/investigation_notes';
|
||||
|
||||
function InvestigationDetailsWithUser({ user }: { user: AuthenticatedUser }) {
|
||||
function InvestigationDetailsWithUser({
|
||||
user,
|
||||
investigationId,
|
||||
}: {
|
||||
user: AuthenticatedUser;
|
||||
investigationId: string;
|
||||
}) {
|
||||
const {
|
||||
dependencies: {
|
||||
start: { investigate },
|
||||
},
|
||||
} = useKibana();
|
||||
const widgetDefinitions = useMemo(() => investigate.getWidgetDefinitions(), [investigate]);
|
||||
const widgetDefinitions = investigate.getWidgetDefinitions();
|
||||
const [range, setRange] = useDateRange();
|
||||
|
||||
const { data: investigationData } = useFetchInvestigation({ id: investigationId });
|
||||
const { mutateAsync: addInvestigationNote } = useAddInvestigationNote();
|
||||
const handleAddInvestigationNote = async (note: string) => {
|
||||
await addInvestigationNote({ investigationId, note: { content: note } });
|
||||
await addNote(note);
|
||||
};
|
||||
|
||||
const {
|
||||
addItem,
|
||||
copyItem,
|
||||
|
@ -42,33 +56,6 @@ function InvestigationDetailsWithUser({ user }: { user: AuthenticatedUser }) {
|
|||
to: range.end.toISOString(),
|
||||
});
|
||||
|
||||
const createWidget = (widgetCreate: InvestigateWidgetCreate) => {
|
||||
return addItem(widgetCreate);
|
||||
};
|
||||
|
||||
const createWidgetRef = useRef(createWidget);
|
||||
createWidgetRef.current = createWidget;
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
renderableInvestigation?.parameters.timeRange.from &&
|
||||
renderableInvestigation?.parameters.timeRange.to &&
|
||||
range.start.toISOString() !== renderableInvestigation.parameters.timeRange.from &&
|
||||
range.end.toISOString() !== renderableInvestigation.parameters.timeRange.to
|
||||
) {
|
||||
setRange({
|
||||
from: renderableInvestigation.parameters.timeRange.from,
|
||||
to: renderableInvestigation.parameters.timeRange.to,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
renderableInvestigation?.parameters.timeRange.from,
|
||||
renderableInvestigation?.parameters.timeRange.to,
|
||||
range.start,
|
||||
range.end,
|
||||
setRange,
|
||||
]);
|
||||
|
||||
const gridItems = useMemo(() => {
|
||||
const widgetDefinitionsByType = keyBy(widgetDefinitions, 'type');
|
||||
|
||||
|
@ -88,7 +75,7 @@ function InvestigationDetailsWithUser({ user }: { user: AuthenticatedUser }) {
|
|||
});
|
||||
}, [renderableInvestigation, widgetDefinitions]);
|
||||
|
||||
if (!investigation || !renderableInvestigation || !gridItems) {
|
||||
if (!investigation || !renderableInvestigation || !gridItems || !investigationData) {
|
||||
return <EuiLoadingSpinner />;
|
||||
}
|
||||
|
||||
|
@ -135,20 +122,24 @@ function InvestigationDetailsWithUser({ user }: { user: AuthenticatedUser }) {
|
|||
<AddObservationUI
|
||||
timeRange={renderableInvestigation.parameters.timeRange}
|
||||
onWidgetAdd={(widget) => {
|
||||
return createWidgetRef.current(widget);
|
||||
return addItem(widget);
|
||||
}}
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={2}>
|
||||
<InvestigationNotes notes={investigation.notes} addNote={addNote} deleteNote={deleteNote} />
|
||||
<InvestigationNotes
|
||||
notes={investigationData.notes}
|
||||
addNote={handleAddInvestigationNote}
|
||||
deleteNote={deleteNote}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
export function InvestigationDetails({}: {}) {
|
||||
export function InvestigationDetails({ investigationId }: { investigationId: string }) {
|
||||
const {
|
||||
core: { security },
|
||||
} = useKibana();
|
||||
|
@ -157,5 +148,12 @@ export function InvestigationDetails({}: {}) {
|
|||
return security.authc.getCurrentUser();
|
||||
}, [security]);
|
||||
|
||||
return user.value ? <InvestigationDetailsWithUser user={user.value} /> : null;
|
||||
if (investigationId == null) {
|
||||
// TODO: return 404 page
|
||||
return null;
|
||||
}
|
||||
|
||||
return user.value ? (
|
||||
<InvestigationDetailsWithUser user={user.value} investigationId={investigationId} />
|
||||
) : null;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/css';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { InvestigationNote } from '@kbn/investigate-plugin/common';
|
||||
import React from 'react';
|
||||
import { InvestigationNote } from '@kbn/investigate-plugin/common';
|
||||
import { useTheme } from '../../../../hooks/use_theme';
|
||||
import { ResizableTextInput } from './resizable_text_input';
|
||||
import { TimelineMessage } from './timeline_message';
|
||||
|
@ -69,7 +69,7 @@ export function InvestigationNotes({ notes, addNote, deleteNote }: Props) {
|
|||
return (
|
||||
<TimelineMessage
|
||||
key={currNote.id}
|
||||
icon={<EuiAvatar name={currNote.createdBy.username} size="s" />}
|
||||
icon={<EuiAvatar name={currNote.createdBy} size="s" />}
|
||||
note={currNote}
|
||||
onDelete={() => deleteNote(currNote.id)}
|
||||
/>
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiMarkdownFormat, EuiText } from '@elastic/eui';
|
||||
import { css } from '@emotion/css';
|
||||
import { InvestigationNote } from '@kbn/investigate-plugin/common';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { format } from 'date-fns';
|
||||
import { InvestigationNote } from '@kbn/investigate-plugin/common';
|
||||
import React from 'react';
|
||||
import { InvestigateTextButton } from '../../../../components/investigate_text_button';
|
||||
import { useTheme } from '../../../../hooks/use_theme';
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
|
||||
import { EuiButton, EuiButtonEmpty, EuiText } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { alertOriginSchema } from '@kbn/investigation-shared';
|
||||
import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data';
|
||||
import { AlertOrigin } from '@kbn/investigate-plugin/common/schema/origin';
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { paths } from '../../../common/paths';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { useFetchInvestigation } from '../../hooks/use_get_investigation_details';
|
||||
import { useInvestigateParams } from '../../hooks/use_investigate_params';
|
||||
import { useFetchAlert } from '../../hooks/use_get_alert_details';
|
||||
import { useFetchInvestigation } from '../../hooks/use_get_investigation_details';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { InvestigationDetails } from './components/investigation_details';
|
||||
import { InvestigationDetailsPathParams } from './types';
|
||||
|
||||
export function InvestigationDetailsPage() {
|
||||
const {
|
||||
|
@ -27,9 +28,7 @@ export function InvestigationDetailsPage() {
|
|||
},
|
||||
} = useKibana();
|
||||
|
||||
const {
|
||||
path: { id },
|
||||
} = useInvestigateParams('/{id}');
|
||||
const { investigationId } = useParams<InvestigationDetailsPathParams>();
|
||||
|
||||
const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate;
|
||||
|
||||
|
@ -37,17 +36,15 @@ export function InvestigationDetailsPage() {
|
|||
data: investigationDetails,
|
||||
isLoading: isFetchInvestigationLoading,
|
||||
isError: isFetchInvestigationError,
|
||||
} = useFetchInvestigation({ id });
|
||||
} = useFetchInvestigation({ id: investigationId });
|
||||
|
||||
const alertId = investigationDetails ? (investigationDetails.origin as AlertOrigin).id : '';
|
||||
const alertId = alertOriginSchema.is(investigationDetails?.origin)
|
||||
? investigationDetails?.origin.id
|
||||
: undefined;
|
||||
|
||||
const {
|
||||
data: alertDetails,
|
||||
isLoading: isFetchAlertLoading,
|
||||
isError: isFetchAlertError,
|
||||
} = useFetchAlert({ id: alertId });
|
||||
const { data: alertDetails } = useFetchAlert({ id: alertId });
|
||||
|
||||
if (isFetchInvestigationLoading || isFetchAlertLoading) {
|
||||
if (isFetchInvestigationLoading) {
|
||||
return (
|
||||
<h1>
|
||||
{i18n.translate('xpack.investigateApp.fetchInvestigation.loadingLabel', {
|
||||
|
@ -57,7 +54,7 @@ export function InvestigationDetailsPage() {
|
|||
);
|
||||
}
|
||||
|
||||
if (isFetchInvestigationError || isFetchAlertError) {
|
||||
if (isFetchInvestigationError) {
|
||||
return (
|
||||
<h1>
|
||||
{i18n.translate('xpack.investigateApp.fetchInvestigation.errorLabel', {
|
||||
|
@ -109,7 +106,7 @@ export function InvestigationDetailsPage() {
|
|||
],
|
||||
}}
|
||||
>
|
||||
<InvestigationDetails />
|
||||
<InvestigationDetails investigationId={investigationId} />
|
||||
</ObservabilityPageTemplate>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export interface InvestigationDetailsPathParams {
|
||||
investigationId: string;
|
||||
}
|
|
@ -4,33 +4,31 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { createRouter } from '@kbn/typed-react-router-config';
|
||||
import * as t from 'io-ts';
|
||||
import React from 'react';
|
||||
import { InvestigationDetailsPage } from '../pages/details/investigation_details_page';
|
||||
import { InvestigationListPage } from '../pages/list/investigation_list_page';
|
||||
|
||||
/**
|
||||
* The array of route definitions to be used when the application
|
||||
* creates the routes.
|
||||
*/
|
||||
const investigateRoutes = {
|
||||
'/': {
|
||||
element: <InvestigationListPage />,
|
||||
},
|
||||
'/new': {
|
||||
element: <InvestigationDetailsPage />,
|
||||
},
|
||||
'/{id}': {
|
||||
element: <InvestigationDetailsPage />,
|
||||
params: t.type({
|
||||
path: t.type({ id: t.string }),
|
||||
}),
|
||||
},
|
||||
export const getRoutes = (): {
|
||||
[path: string]: {
|
||||
handler: () => React.ReactElement;
|
||||
params: Record<string, string>;
|
||||
exact: boolean;
|
||||
};
|
||||
} => {
|
||||
return {
|
||||
'/': {
|
||||
handler: () => {
|
||||
return <InvestigationListPage />;
|
||||
},
|
||||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
'/:investigationId': {
|
||||
handler: () => {
|
||||
return <InvestigationDetailsPage />;
|
||||
},
|
||||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export type InvestigateRoutes = typeof investigateRoutes;
|
||||
|
||||
export const investigateRouter = createRouter(investigateRoutes);
|
||||
|
||||
export type InvestigateRouter = typeof investigateRouter;
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { alertOriginSchema, blankOriginSchema } from '@kbn/investigate-plugin/common/schema/origin';
|
||||
import { alertOriginSchema, blankOriginSchema } from '@kbn/investigation-shared';
|
||||
import * as t from 'io-ts';
|
||||
import { investigationNoteSchema } from './investigation_note';
|
||||
|
||||
export const investigationSchema = t.type({
|
||||
id: t.string,
|
||||
|
@ -18,6 +19,7 @@ export const investigationSchema = t.type({
|
|||
}),
|
||||
origin: t.union([alertOriginSchema, blankOriginSchema]),
|
||||
status: t.union([t.literal('ongoing'), t.literal('closed')]),
|
||||
notes: t.array(investigationNoteSchema),
|
||||
});
|
||||
|
||||
export type Investigation = t.TypeOf<typeof investigationSchema>;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const investigationNoteSchema = t.type({
|
||||
id: t.string,
|
||||
createdAt: t.number,
|
||||
createdBy: t.string,
|
||||
content: t.string,
|
||||
});
|
||||
|
||||
export type InvestigationNote = t.TypeOf<typeof investigationNoteSchema>;
|
||||
export type StoredInvestigationNote = t.OutputOf<typeof investigationNoteSchema>;
|
|
@ -5,14 +5,22 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createInvestigationParamsSchema } from '@kbn/investigate-plugin/common';
|
||||
import { findInvestigationsParamsSchema } from '@kbn/investigate-plugin/common';
|
||||
import { getInvestigationParamsSchema } from '@kbn/investigate-plugin/common';
|
||||
import {
|
||||
createInvestigationNoteParamsSchema,
|
||||
createInvestigationParamsSchema,
|
||||
deleteInvestigationParamsSchema,
|
||||
findInvestigationsParamsSchema,
|
||||
getInvestigationNotesParamsSchema,
|
||||
getInvestigationParamsSchema,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { createInvestigation } from '../services/create_investigation';
|
||||
import { investigationRepositoryFactory } from '../services/investigation_repository';
|
||||
import { createInvestigateAppServerRoute } from './create_investigate_app_server_route';
|
||||
import { createInvestigationNote } from '../services/create_investigation_note';
|
||||
import { deleteInvestigation } from '../services/delete_investigation';
|
||||
import { findInvestigations } from '../services/find_investigations';
|
||||
import { getInvestigation } from '../services/get_investigation';
|
||||
import { getInvestigationNotes } from '../services/get_investigation_notes';
|
||||
import { investigationRepositoryFactory } from '../services/investigation_repository';
|
||||
import { createInvestigateAppServerRoute } from './create_investigate_app_server_route';
|
||||
|
||||
const createInvestigationRoute = createInvestigateAppServerRoute({
|
||||
endpoint: 'POST /api/observability/investigations 2023-10-31',
|
||||
|
@ -56,11 +64,56 @@ const getInvestigationRoute = createInvestigateAppServerRoute({
|
|||
},
|
||||
});
|
||||
|
||||
const deleteInvestigationRoute = createInvestigateAppServerRoute({
|
||||
endpoint: 'DELETE /api/observability/investigations/{id} 2023-10-31',
|
||||
options: {
|
||||
tags: [],
|
||||
},
|
||||
params: deleteInvestigationParamsSchema,
|
||||
handler: async (params) => {
|
||||
const soClient = (await params.context.core).savedObjects.client;
|
||||
const repository = investigationRepositoryFactory({ soClient, logger: params.logger });
|
||||
|
||||
return await deleteInvestigation(params.params.path.id, repository);
|
||||
},
|
||||
});
|
||||
|
||||
const createInvestigationNoteRoute = createInvestigateAppServerRoute({
|
||||
endpoint: 'POST /api/observability/investigations/{id}/notes 2023-10-31',
|
||||
options: {
|
||||
tags: [],
|
||||
},
|
||||
params: createInvestigationNoteParamsSchema,
|
||||
handler: async (params) => {
|
||||
const soClient = (await params.context.core).savedObjects.client;
|
||||
const repository = investigationRepositoryFactory({ soClient, logger: params.logger });
|
||||
|
||||
return await createInvestigationNote(params.params.path.id, params.params.body, repository);
|
||||
},
|
||||
});
|
||||
|
||||
const getInvestigationNotesRoute = createInvestigateAppServerRoute({
|
||||
endpoint: 'GET /api/observability/investigations/{id}/notes 2023-10-31',
|
||||
options: {
|
||||
tags: [],
|
||||
},
|
||||
params: getInvestigationNotesParamsSchema,
|
||||
handler: async (params) => {
|
||||
const soClient = (await params.context.core).savedObjects.client;
|
||||
const repository = investigationRepositoryFactory({ soClient, logger: params.logger });
|
||||
|
||||
return await getInvestigationNotes(params.params.path.id, repository);
|
||||
},
|
||||
});
|
||||
|
||||
export function getGlobalInvestigateAppServerRouteRepository() {
|
||||
return {
|
||||
...createInvestigationRoute,
|
||||
...findInvestigationsRoute,
|
||||
...getInvestigationRoute,
|
||||
...deleteInvestigationRoute,
|
||||
...createInvestigationNoteRoute,
|
||||
...getInvestigationNotesRoute,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
CreateInvestigationInput,
|
||||
CreateInvestigationResponse,
|
||||
} from '@kbn/investigate-plugin/common';
|
||||
import { CreateInvestigationInput, CreateInvestigationResponse } from '@kbn/investigation-shared';
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
enum InvestigationStatus {
|
||||
|
@ -25,6 +22,7 @@ export async function createInvestigation(
|
|||
createdAt: Date.now(),
|
||||
createdBy: 'elastic',
|
||||
status: InvestigationStatus.ongoing,
|
||||
notes: [],
|
||||
};
|
||||
await repository.save(investigation);
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
CreateInvestigationNoteInput,
|
||||
CreateInvestigationNoteResponse,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { v4 } from 'uuid';
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
export async function createInvestigationNote(
|
||||
investigationId: string,
|
||||
params: CreateInvestigationNoteInput,
|
||||
repository: InvestigationRepository
|
||||
): Promise<CreateInvestigationNoteResponse> {
|
||||
const investigation = await repository.findById(investigationId);
|
||||
|
||||
const investigationNote = {
|
||||
id: v4(),
|
||||
content: params.content,
|
||||
createdBy: 'TODO: get user from request',
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
investigation.notes.push(investigationNote);
|
||||
|
||||
await repository.save(investigation);
|
||||
|
||||
return investigationNote;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
export async function deleteInvestigation(
|
||||
id: string,
|
||||
repository: InvestigationRepository
|
||||
): Promise<void> {
|
||||
await repository.deleteById(id);
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common';
|
||||
import {
|
||||
FindInvestigationsParams,
|
||||
FindInvestigationsResponse,
|
||||
findInvestigationsResponseSchema,
|
||||
} from '@kbn/investigate-plugin/common/schema/find';
|
||||
} from '@kbn/investigation-shared';
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
export async function findInvestigations(
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { GetInvestigationParams } from '@kbn/investigate-plugin/common';
|
||||
import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/get';
|
||||
import {
|
||||
GetInvestigationParams,
|
||||
GetInvestigationResponse,
|
||||
getInvestigationResponseSchema,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
export async function getInvestigation(
|
||||
|
@ -15,5 +18,5 @@ export async function getInvestigation(
|
|||
): Promise<GetInvestigationResponse> {
|
||||
const investigation = await repository.findById(params.id);
|
||||
|
||||
return investigation;
|
||||
return getInvestigationResponseSchema.encode(investigation);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
GetInvestigationNotesResponse,
|
||||
getInvestigationNotesResponseSchema,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { InvestigationRepository } from './investigation_repository';
|
||||
|
||||
export async function getInvestigationNotes(
|
||||
investigationId: string,
|
||||
repository: InvestigationRepository
|
||||
): Promise<GetInvestigationNotesResponse> {
|
||||
const investigation = await repository.findById(investigationId);
|
||||
|
||||
return getInvestigationNotesResponseSchema.encode(investigation.notes);
|
||||
}
|
|
@ -21,7 +21,6 @@
|
|||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/kibana-react-plugin",
|
||||
"@kbn/typed-react-router-config",
|
||||
"@kbn/i18n",
|
||||
"@kbn/embeddable-plugin",
|
||||
"@kbn/observability-ai-assistant-plugin",
|
||||
|
@ -54,5 +53,7 @@
|
|||
"@kbn/core-saved-objects-server",
|
||||
"@kbn/rule-registry-plugin",
|
||||
"@kbn/rule-data-utils",
|
||||
"@kbn/shared-ux-router",
|
||||
"@kbn/investigation-shared",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
|
||||
import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public';
|
||||
import { QueryKey, useMutation } from '@tanstack/react-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
CreateInvestigationInput,
|
||||
CreateInvestigationResponse,
|
||||
} from '@kbn/investigate-plugin/common';
|
||||
import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common';
|
||||
FindInvestigationsResponse,
|
||||
} from '@kbn/investigation-shared';
|
||||
import { QueryKey, useMutation } from '@tanstack/react-query';
|
||||
import { useKibana } from '../../../utils/kibana_react';
|
||||
|
||||
type ServerError = IHttpFetchError<ResponseErrorBody>;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FindInvestigationsResponse } from '@kbn/investigation-shared';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common';
|
||||
import { useKibana } from '../../../utils/kibana_react';
|
||||
|
||||
export interface InvestigationsByAlertParams {
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
"@kbn/observability-alerting-rule-utils",
|
||||
"@kbn/core-ui-settings-server-mocks",
|
||||
"@kbn/investigate-plugin",
|
||||
"@kbn/investigation-shared",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
|
|
|
@ -5320,6 +5320,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/investigation-shared@link:packages/kbn-investigation-shared":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/io-ts-utils@link:packages/kbn-io-ts-utils":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue