-
Notifications
You must be signed in to change notification settings - Fork 8.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open/Closed filter for observability alerts page #99217
Changes from all commits
f755898
73b2517
bdf00a8
a9a1c2b
baeeb6c
e3a70bc
e0691e7
cf38a58
cec255b
f53bbfa
ba2e5ae
3b17d0d
26a971a
4398630
395d096
1e1379d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,9 @@ | |
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
import * as t from 'io-ts'; | ||
|
||
export type Maybe<T> = T | null | undefined; | ||
|
||
export const alertStatusRt = t.union([t.literal('all'), t.literal('open'), t.literal('closed')]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't really in scope of this ticket directly, but I'm nervous that we're still using "open" and "closed" to mean "active" and "recovered" because they feel like very different concepts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only place "active" and "recovered" is used is on the control itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to keep active and recovered as the language here (imo), but that the concepts are different in the underlying data so we'll eventually not want them linked. We've talked about it in 3 or 4 places but these things are hard to keep track of. But there will eventually be a difference between workflow status and active/recovered, since one is controlled by humans and the other is controlled by data + conditions of the rule. Does the alert schema not have any other status fields? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is still accurate: https://github.com/elastic/kibana/tree/master/x-pack/plugins/rule_registry#schema There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh thanks. I think we may need to use alerts that have this value set:
I just now realized we probably want a way to have the investigation window (date range) apply to recovery date and not just start date ... but that's for later :P There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's leave it for now and address it as it comes up, but it will be important not to forget because I'm not 100% sure we will set that status to closed on resolution ... or if the semantics of when it gets set to closed / open could change and be surprising to us later. |
||
export type AlertStatus = t.TypeOf<typeof alertStatusRt>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* 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 React, { ComponentProps, useState } from 'react'; | ||
import type { AlertStatus } from '../../../common/typings'; | ||
import { StatusFilter } from './status_filter'; | ||
|
||
type Args = ComponentProps<typeof StatusFilter>; | ||
|
||
export default { | ||
title: 'app/Alerts/StatusFilter', | ||
component: StatusFilter, | ||
argTypes: { | ||
onChange: { action: 'change' }, | ||
}, | ||
}; | ||
|
||
export function Example({ onChange }: Args) { | ||
const [status, setStatus] = useState<AlertStatus>('open'); | ||
|
||
return ( | ||
<StatusFilter | ||
status={status} | ||
onChange={(value) => { | ||
setStatus(value); | ||
onChange(value); | ||
}} | ||
/> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* 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 { render } from '@testing-library/react'; | ||
import React from 'react'; | ||
import type { AlertStatus } from '../../../common/typings'; | ||
import { StatusFilter } from './status_filter'; | ||
|
||
describe('StatusFilter', () => { | ||
describe('render', () => { | ||
it('renders', () => { | ||
const onChange = jest.fn(); | ||
const status: AlertStatus = 'all'; | ||
const props = { onChange, status }; | ||
|
||
expect(() => render(<StatusFilter {...props} />)).not.toThrowError(); | ||
}); | ||
|
||
(['all', 'open', 'closed'] as AlertStatus[]).map((status) => { | ||
describe(`when clicking the ${status} button`, () => { | ||
it('calls the onChange callback with "${status}"', () => { | ||
const onChange = jest.fn(); | ||
const props = { onChange, status }; | ||
|
||
const { getByTestId } = render(<StatusFilter {...props} />); | ||
const button = getByTestId(`StatusFilter ${status} button`); | ||
|
||
button.click(); | ||
|
||
expect(onChange).toHaveBeenCalledWith(status); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* 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 { EuiFilterButton, EuiFilterGroup } from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
import React from 'react'; | ||
import type { AlertStatus } from '../../../common/typings'; | ||
|
||
export interface StatusFilterProps { | ||
status: AlertStatus; | ||
onChange: (value: AlertStatus) => void; | ||
} | ||
|
||
export function StatusFilter({ status = 'open', onChange }: StatusFilterProps) { | ||
return ( | ||
<EuiFilterGroup | ||
aria-label={i18n.translate('xpack.observability.alerts.statusFilterAriaLabel', { | ||
defaultMessage: 'Filter alerts by open and closed status', | ||
})} | ||
> | ||
<EuiFilterButton | ||
smith marked this conversation as resolved.
Show resolved
Hide resolved
|
||
data-test-subj="StatusFilter open button" | ||
hasActiveFilters={status === 'open'} | ||
onClick={() => onChange('open')} | ||
withNext={true} | ||
> | ||
{i18n.translate('xpack.observability.alerts.statusFilter.openButtonLabel', { | ||
defaultMessage: 'Open', | ||
})} | ||
</EuiFilterButton> | ||
<EuiFilterButton | ||
data-test-subj="StatusFilter closed button" | ||
hasActiveFilters={status === 'closed'} | ||
onClick={() => onChange('closed')} | ||
withNext={true} | ||
> | ||
{i18n.translate('xpack.observability.alerts.statusFilter.closedButtonLabel', { | ||
defaultMessage: 'Closed', | ||
})} | ||
</EuiFilterButton> | ||
<EuiFilterButton | ||
data-test-subj="StatusFilter all button" | ||
hasActiveFilters={status === 'all'} | ||
onClick={() => onChange('all')} | ||
> | ||
{i18n.translate('xpack.observability.alerts.statusFilter.allButtonLabel', { | ||
defaultMessage: 'All', | ||
})} | ||
</EuiFilterButton> | ||
</EuiFilterGroup> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this! 👏