Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b694652
Rename component
kdelemme Aug 22, 2024
68c145c
Remove extra component
kdelemme Aug 22, 2024
39f5cd4
fix eslint
kdelemme Aug 22, 2024
70efe09
wip: attempt at registration of esql item
kdelemme Aug 22, 2024
83f5505
wip: generate items
kdelemme Aug 22, 2024
6420de0
rename types
kdelemme Aug 22, 2024
3fa4e2a
Add embeddable item type
kdelemme Aug 23, 2024
8058958
wip
kdelemme Aug 23, 2024
49f8633
Remove item types
kdelemme Aug 23, 2024
b1966ed
Introduce generics
kdelemme Aug 23, 2024
0755f8c
extract render logic to hook
kdelemme Aug 23, 2024
ded1144
Create items mutation and query hooks
kdelemme Aug 23, 2024
deb9190
Extract items to component
kdelemme Aug 23, 2024
35e3470
cleanup methods
kdelemme Aug 23, 2024
adf3c20
Move and rename components into details page
kdelemme Aug 26, 2024
11f664a
Move type
kdelemme Aug 26, 2024
953fa35
Remove previous widget registry
kdelemme Aug 26, 2024
8b53e80
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 26, 2024
c3481f7
Merge branch 'main' into rca/esql-item
kdelemme Aug 26, 2024
ed819d2
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Aug 26, 2024
f90db58
revert eslint change
kdelemme Aug 26, 2024
9f5b457
Merge branch 'main' into rca/esql-item
kdelemme Aug 26, 2024
d81127f
revert change
kdelemme Aug 26, 2024
00184c3
Handle editing notes
kdelemme Aug 27, 2024
0d4fc2f
Merge branch 'main' into rca/edit-notes
kdelemme Aug 28, 2024
ac4fb99
fix merge conflict
kdelemme Aug 28, 2024
23ab793
revert merge conflict issue
kdelemme Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/kbn-investigation-shared/src/rest_specs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type * from './create_item';
export type * from './delete_item';
export type * from './get_items';
export type * from './investigation_item';
export type * from './update_note';

export * from './create';
export * from './create_note';
Expand All @@ -31,3 +32,4 @@ export * from './create_item';
export * from './delete_item';
export * from './get_items';
export * from './investigation_item';
export * from './update_note';
30 changes: 30 additions & 0 deletions packages/kbn-investigation-shared/src/rest_specs/update_note.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 updateInvestigationNoteParamsSchema = t.type({
path: t.type({
investigationId: t.string,
noteId: t.string,
}),
body: t.type({
content: t.string,
}),
});

const updateInvestigationNoteResponseSchema = investigationNoteResponseSchema;

type UpdateInvestigationNoteParams = t.TypeOf<
typeof updateInvestigationNoteParamsSchema.props.body
>;
type UpdateInvestigationNoteResponse = t.OutputOf<typeof updateInvestigationNoteResponseSchema>;

export { updateInvestigationNoteParamsSchema, updateInvestigationNoteResponseSchema };
export type { UpdateInvestigationNoteParams, UpdateInvestigationNoteResponse };
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 { UpdateInvestigationNoteParams } from '@kbn/investigation-shared';
import { useMutation } from '@tanstack/react-query';
import { useKibana } from './use_kibana';

type ServerError = IHttpFetchError<ResponseErrorBody>;

export function useUpdateInvestigationNote() {
const {
core: {
http,
notifications: { toasts },
},
} = useKibana();

return useMutation<
void,
ServerError,
{ investigationId: string; noteId: string; note: UpdateInvestigationNoteParams },
{ investigationId: string }
>(
['deleteInvestigationNote'],
({ investigationId, noteId, note }) => {
const body = JSON.stringify(note);
return http.put<void>(
`/api/observability/investigations/${investigationId}/notes/${noteId}`,
{ body, version: '2023-10-31' }
);
},
{
onSuccess: (response, {}) => {
toasts.addSuccess('Note updated');
},
onError: (error, {}, context) => {
toasts.addError(new Error(error.body?.message ?? 'An error occurred'), { title: 'Error' });
},
}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function registerEmbeddableItem({
services,
}: Options) {
investigate.registerItemDefinition<EmbeddableItemParams, {}>({
type: 'esql',
type: 'embeddable',
generate: async (option: {
itemParams: EmbeddableItemParams;
globalParams: GlobalWidgetParameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ interface EsqlItemData {
};
}

export const ESQL_ITEM_TYPE = 'esql';

export function EsqlWidget({
suggestion,
dataView,
Expand Down Expand Up @@ -228,7 +230,7 @@ export function registerEsqlItem({
services,
}: Options) {
investigate.registerItemDefinition<EsqlItemParams, EsqlItemData>({
type: 'esql',
type: ESQL_ITEM_TYPE,
generate: async (option: {
itemParams: EsqlItemParams;
globalParams: GlobalWidgetParameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ErrorMessage } from '../../../../components/error_message';
import { SuggestVisualizationList } from '../../../../components/suggest_visualization_list';
import { useKibana } from '../../../../hooks/use_kibana';
import { getDateHistogramResults } from '../../../../items/esql_item/get_date_histogram_results';
import { EsqlWidget } from '../../../../items/esql_item/register_esql_item';
import { ESQL_ITEM_TYPE, EsqlWidget } from '../../../../items/esql_item/register_esql_item';
import { getEsFilterFromOverrides } from '../../../../utils/get_es_filter_from_overrides';

function getItemFromSuggestion({
Expand All @@ -29,7 +29,7 @@ function getItemFromSuggestion({
}): Item {
return {
title: suggestion.title,
type: 'esql',
type: ESQL_ITEM_TYPE,
params: {
esql: query,
suggestion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ export function InvestigationDetails({ user, investigationId }: Props) {
return (
<EuiFlexGroup direction="row">
<EuiFlexItem grow={8}>
<InvestigationItems investigationId={investigationId} investigation={investigation} />
<InvestigationItems investigation={investigation} />
</EuiFlexItem>

<EuiFlexItem grow={2}>
<InvestigationNotes investigationId={investigationId} investigation={investigation} />
<InvestigationNotes investigation={investigation} user={user} />
</EuiFlexItem>
</EuiFlexGroup>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import { InvestigationItemsList } from '../investigation_items_list/investigatio
import { InvestigationSearchBar } from '../investigation_search_bar/investigation_search_bar';

export interface Props {
investigationId: string;
investigation: GetInvestigationResponse;
}

export function InvestigationItems({ investigationId, investigation }: Props) {
export function InvestigationItems({ investigation }: Props) {
const { data: items, refetch } = useFetchInvestigationItems({
investigationId,
investigationId: investigation.id,
initialItems: investigation.items,
});
const renderableItems = useRenderItems({ items, params: investigation.params });
Expand All @@ -34,12 +33,12 @@ export function InvestigationItems({ investigationId, investigation }: Props) {
useDeleteInvestigationItem();

const onAddItem = async (item: Item) => {
await addInvestigationItem({ investigationId, item });
await addInvestigationItem({ investigationId: investigation.id, item });
refetch();
};

const onDeleteItem = async (itemId: string) => {
await deleteInvestigationItem({ investigationId, itemId });
await deleteInvestigationItem({ investigationId: investigation.id, itemId });
refetch();
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* 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 { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { InvestigationNoteResponse } from '@kbn/investigation-shared';
import React, { useState } from 'react';
import { ResizableTextInput } from './resizable_text_input';
import { useUpdateInvestigationNote } from '../../../../hooks/use_update_investigation_note';

interface Props {
investigationId: string;
note: InvestigationNoteResponse;
onCancel: () => void;
onUpdate: () => void;
}

export function EditNoteForm({ investigationId, note, onCancel, onUpdate }: Props) {
const [noteInput, setNoteInput] = useState(note.content);
const { mutateAsync: updateNote, isLoading: isUpdating } = useUpdateInvestigationNote();

const handleUpdateNote = async () => {
await updateNote({ investigationId, noteId: note.id, note: { content: noteInput.trim() } });
onUpdate();
};

return (
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<ResizableTextInput
disabled={isUpdating}
value={noteInput}
onChange={(value) => {
setNoteInput(value);
}}
onSubmit={() => {
handleUpdateNote();
}}
placeholder={note.content}
/>
</EuiFlexItem>

<EuiFlexGroup direction="row" gutterSize="s" justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton
disabled={isUpdating}
data-test-subj="cancelEditNoteButton"
color="text"
aria-label={i18n.translate(
'xpack.investigateApp.investigationNotes.cancelEditButtonLabel',
{ defaultMessage: 'Cancel' }
)}
size="m"
onClick={() => onCancel()}
>
{i18n.translate('xpack.investigateApp.investigationNotes.cancelEditButtonLabel', {
defaultMessage: 'Cancel',
})}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="updateNoteButton"
color="primary"
aria-label={i18n.translate(
'xpack.investigateApp.investigationNotes.updateNoteButtonLabel',
{ defaultMessage: 'Update note' }
)}
disabled={isUpdating || noteInput.trim() === ''}
isLoading={isUpdating}
size="m"
onClick={() => {
handleUpdateNote();
}}
>
{i18n.translate('xpack.investigateApp.investigationNotes.updateNoteButtonLabel', {
defaultMessage: 'Update note',
})}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import {
EuiAvatar,
EuiButton,
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -16,43 +15,36 @@ import {
} from '@elastic/eui';
import { css } from '@emotion/css';
import { i18n } from '@kbn/i18n';
import { InvestigationNoteResponse, GetInvestigationResponse } from '@kbn/investigation-shared';
import { GetInvestigationResponse, InvestigationNoteResponse } from '@kbn/investigation-shared';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
import React, { useState } from 'react';
import { useAddInvestigationNote } from '../../../../hooks/use_add_investigation_note';
import { useDeleteInvestigationNote } from '../../../../hooks/use_delete_investigation_note';
import { useFetchInvestigationNotes } from '../../../../hooks/use_fetch_investigation_notes';
import { useTheme } from '../../../../hooks/use_theme';
import { Note } from './note';
import { ResizableTextInput } from './resizable_text_input';
import { TimelineMessage } from './timeline_message';

export interface Props {
investigationId: string;
investigation: GetInvestigationResponse;
user: AuthenticatedUser;
}

export function InvestigationNotes({ investigationId, investigation }: Props) {
export function InvestigationNotes({ investigation, user }: Props) {
const theme = useTheme();
const [noteInput, setNoteInput] = useState('');

const { data: notes, refetch } = useFetchInvestigationNotes({
investigationId,
investigationId: investigation.id,
initialNotes: investigation.notes,
});
const { mutateAsync: addInvestigationNote, isLoading: isAdding } = useAddInvestigationNote();
const { mutateAsync: deleteInvestigationNote, isLoading: isDeleting } =
useDeleteInvestigationNote();

const onAddNote = async (content: string) => {
await addInvestigationNote({ investigationId, note: { content } });
await addInvestigationNote({ investigationId: investigation.id, note: { content } });
refetch();
setNoteInput('');
};

const onDeleteNote = async (noteId: string) => {
await deleteInvestigationNote({ investigationId, noteId });
refetch();
};

const panelClassName = css`
background-color: ${theme.colors.lightShade};
`;
Expand All @@ -72,12 +64,12 @@ export function InvestigationNotes({ investigationId, investigation }: Props) {
<EuiFlexGroup direction="column" gutterSize="m">
{notes?.map((currNote: InvestigationNoteResponse) => {
return (
<TimelineMessage
<Note
key={currNote.id}
icon={<EuiAvatar name={currNote.createdBy} size="s" />}
investigationId={investigation.id}
note={currNote}
onDelete={() => onDeleteNote(currNote.id)}
isDeleting={isDeleting}
disabled={currNote.createdBy !== user.username}
onUpdateOrDeleteCompleted={() => refetch()}
/>
);
})}
Expand Down Expand Up @@ -110,7 +102,7 @@ export function InvestigationNotes({ investigationId, investigation }: Props) {
<EuiButton
data-test-subj="investigateAppInvestigationNotesAddButton"
fullWidth
color="text"
color="primary"
aria-label={i18n.translate('xpack.investigateApp.investigationNotes.addButtonLabel', {
defaultMessage: 'Add',
})}
Expand Down
Loading