-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[SR] Delete and execute SLM policies #41934
Conversation
Pinging @elastic/es-ui |
@@ -49,7 +49,9 @@ export const RepositoryDeleteProvider: React.FunctionComponent<Props> = ({ child | |||
|
|||
const deleteRepository = () => { | |||
const repositoriesToDelete = [...repositoryNames]; | |||
deleteRepositories(repositoriesToDelete).then(({ data: { itemsDeleted, errors }, error }) => { |
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.
while working on policy deletion, I found that for server errors such as 404
or 500
, which don't return a data
object, early destructuring here causes an undefined object error, so no toast notification is shown. I adjusted this for policy deletion and fixed it for other delete providers in this app such as here.
@@ -180,7 +242,7 @@ export const PolicyDetails: React.FunctionComponent<Props> = ({ policyName, onCl | |||
data-test-subj="policyDetail" | |||
aria-labelledby="srPolicyDetailsFlyoutTitle" | |||
size="m" | |||
maxWidth={400} | |||
maxWidth={550} |
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.
I bumped up the max width of all flyouts in this app as recent changes in EUI made them too narrow
💚 Build Succeeded |
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.
@jen-huang tested locally and everything LGTM. Left a couple minor comments.
return ( | ||
<EuiButtonEmpty | ||
color="danger" | ||
data-test-subj="srPoicyDetailsDeleteActionButton" |
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.
typo here i think: srPoicyDetailsDeleteActionButton --> srPolicyDetailsDeleteActionButton
} | ||
fill | ||
color="primary" | ||
data-test-subj="srPoicyDetailsExecuteActionButton" |
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.
srPoicyDetailsExecuteActionButton --> srPolicyDetailsExecuteActionButton
aria-label={i18n.translate( | ||
'xpack.snapshotRestore.policyList.table.actionExecuteAriaLabel', | ||
{ | ||
defaultMessage: 'Run policy `{name}`', |
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.
should this be
`Run policy '{name}'`
aria-label={i18n.translate( | ||
'xpack.snapshotRestore.policyList.table.actionDeleteAriaLabel', | ||
{ | ||
defaultMessage: 'Delete policy `{name}`', |
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.
should this be
`Delete policy '{name}'`
💔 Build Failed |
💚 Build Succeeded |
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.
Looks awesome! I know this is a bit late, but I had some suggestions for your perusal.
}; | ||
|
||
const deletePolicy = () => { | ||
const policiesToDelete = [...policyNames]; |
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.
Why do we create a copy of policyNames
here? Does something bad happen if we delete policyNames
directly?
const deletePolicy = () => { | ||
const policiesToDelete = [...policyNames]; | ||
deletePolicies(policiesToDelete).then(({ data, error }) => { | ||
const { itemsDeleted, errors } = data || { itemsDeleted: undefined, errors: undefined }; |
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.
Nit: we could also assign a default value to the data
parameter above, which would be a bit terser. We could also set a default value to itemsDeleted
and errors
, which would make lines 52 and 72 terser as well.
deletePolicies(policiesToDelete).then(({ data = {}, error }) => {
const { itemsDeleted = [], errors = [] } = data;
// ln 52
if (itemsDeleted.length) {
// ln 72
if (error || errors.length) {
I just realized that this won't quite work with the current logic for displaying error messages, but I have a suggestion that could make it work in the next comment.
// Surface error notifications | ||
// `error` is generic server error | ||
// `data.errors` are specific errors with removing particular policy(ies) | ||
if (error || (errors && errors.length)) { |
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.
I was having trouble following this logic because it contains two parallel conditional branches. How about something like this to make the two branches easier to discern and compare?
function createErrorMessageMultiple(count) {
return i18n.translate('xpack.snapshotRestore.deletePolicy.errorMultipleNotificationTitle', {
defaultMessage: 'Error deleting {count} policies',
values: { count },
});
}
function createErrorMessageSingle(name) {
return i18n.translate('xpack.snapshotRestore.deletePolicy.errorSingleNotificationTitle', {
defaultMessage: "Error deleting policy '{name}'",
values: { name },
});
}
// Surface error notifications
let errorMessage;
if (errors.length) {
// `data.errors` are specific errors with removing particular policy(ies)
errorMessage = errors.length > 1
? createErrorMessageMultiple(errors.length)
: createErrorMessageSingle(errors[0].name);
} else if (error) {
// `error` is generic server error
errorMessage = policiesToDelete.length > 1
? createErrorMessageMultiple(policiesToDelete.length)
: createErrorMessageSingle(policiesToDelete[0])
}
if (errorMessage) {
toastNotifications.addDanger(errorMessage);
}
@@ -49,7 +49,9 @@ export const RepositoryDeleteProvider: React.FunctionComponent<Props> = ({ child | |||
|
|||
const deleteRepository = () => { | |||
const repositoriesToDelete = [...repositoryNames]; | |||
deleteRepositories(repositoriesToDelete).then(({ data: { itemsDeleted, errors }, error }) => { | |||
deleteRepositories(repositoriesToDelete).then(({ data, error }) => { |
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.
Can this be fixed like this?
// Default `data` to an empty object if it's not provided, which will have
// undefined `itemsDeleted` and `errors` properties.
deleteRepositories(repositoriesToDelete).then(({ data: { itemsDeleted, errors } = {}, error }) => {
onClick={() => | ||
executePolicyPrompt(policyName, () => { | ||
onPolicyExecuted(); | ||
reload(); |
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.
Is this needed? It looks like policy_list
calls reload
itself.
|
||
export const deleteHandler: RouterRouteHandler = async (req, callWithRequest) => { | ||
const { names } = req.params; | ||
const policyNames = names.split(','); |
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.
Dumb question: are commas disallowed in policy names?
Summary
This PR adds the ability to delete and execute SLM policies from the UI. Executing a policy is referred to as "Run" (i.e. "Run policy") in the UI and this action means that a snapshot will be taken immediately using the configuration specified in the policy. Delete is self explanatory and uses our single/multi-delete pattern used in other apps.
Screenshots
Actions in table and details
.Run and delete actions in table row
Bulk delete from selecting multiple rows
Run and delete actions in policy details
Delete policy(ies)
.Single delete modal
Bulk delete modal
Run policy
Run policy modal