-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Add single and bulk policy delete * Add policy execution * Remove early destructuring of provider request responses * Address PR feedback * Adjust policy requests for useRequest changes * Fix policy reload
- Loading branch information
Showing
15 changed files
with
702 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_delete_provider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* 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, { Fragment, useRef, useState } from 'react'; | ||
import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; | ||
import { useAppDependencies } from '../index'; | ||
import { deletePolicies } from '../services/http'; | ||
|
||
interface Props { | ||
children: (deletePolicy: DeletePolicy) => React.ReactElement; | ||
} | ||
|
||
export type DeletePolicy = (names: string[], onSuccess?: OnSuccessCallback) => void; | ||
|
||
type OnSuccessCallback = (policiesDeleted: string[]) => void; | ||
|
||
export const PolicyDeleteProvider: React.FunctionComponent<Props> = ({ children }) => { | ||
const { | ||
core: { | ||
i18n, | ||
notification: { toastNotifications }, | ||
}, | ||
} = useAppDependencies(); | ||
const { FormattedMessage } = i18n; | ||
const [policyNames, setPolicyNames] = useState<string[]>([]); | ||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false); | ||
const onSuccessCallback = useRef<OnSuccessCallback | null>(null); | ||
|
||
const deletePolicyPrompt: DeletePolicy = (names, onSuccess = () => undefined) => { | ||
if (!names || !names.length) { | ||
throw new Error('No policy names specified for deletion'); | ||
} | ||
setIsModalOpen(true); | ||
setPolicyNames(names); | ||
onSuccessCallback.current = onSuccess; | ||
}; | ||
|
||
const closeModal = () => { | ||
setIsModalOpen(false); | ||
setPolicyNames([]); | ||
}; | ||
|
||
const deletePolicy = () => { | ||
const policiesToDelete = [...policyNames]; | ||
deletePolicies(policiesToDelete).then(({ data, error }) => { | ||
const { itemsDeleted, errors } = data || { itemsDeleted: undefined, errors: undefined }; | ||
|
||
// Surface success notifications | ||
if (itemsDeleted && itemsDeleted.length) { | ||
const hasMultipleSuccesses = itemsDeleted.length > 1; | ||
const successMessage = hasMultipleSuccesses | ||
? i18n.translate('xpack.snapshotRestore.deletePolicy.successMultipleNotificationTitle', { | ||
defaultMessage: 'Deleted {count} policies', | ||
values: { count: itemsDeleted.length }, | ||
}) | ||
: i18n.translate('xpack.snapshotRestore.deletePolicy.successSingleNotificationTitle', { | ||
defaultMessage: "Deleted policy '{name}'", | ||
values: { name: itemsDeleted[0] }, | ||
}); | ||
toastNotifications.addSuccess(successMessage); | ||
if (onSuccessCallback.current) { | ||
onSuccessCallback.current([...itemsDeleted]); | ||
} | ||
} | ||
|
||
// Surface error notifications | ||
// `error` is generic server error | ||
// `data.errors` are specific errors with removing particular policy(ies) | ||
if (error || (errors && errors.length)) { | ||
const hasMultipleErrors = | ||
(errors && errors.length > 1) || (error && policiesToDelete.length > 1); | ||
const errorMessage = hasMultipleErrors | ||
? i18n.translate('xpack.snapshotRestore.deletePolicy.errorMultipleNotificationTitle', { | ||
defaultMessage: 'Error deleting {count} policies', | ||
values: { | ||
count: (errors && errors.length) || policiesToDelete.length, | ||
}, | ||
}) | ||
: i18n.translate('xpack.snapshotRestore.deletePolicy.errorSingleNotificationTitle', { | ||
defaultMessage: "Error deleting policy '{name}'", | ||
values: { name: (errors && errors[0].name) || policiesToDelete[0] }, | ||
}); | ||
toastNotifications.addDanger(errorMessage); | ||
} | ||
}); | ||
closeModal(); | ||
}; | ||
|
||
const renderModal = () => { | ||
if (!isModalOpen) { | ||
return null; | ||
} | ||
|
||
const isSingle = policyNames.length === 1; | ||
|
||
return ( | ||
<EuiOverlayMask> | ||
<EuiConfirmModal | ||
title={ | ||
isSingle ? ( | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.deletePolicy.confirmModal.deleteSingleTitle" | ||
defaultMessage="Delete policy '{name}'?" | ||
values={{ name: policyNames[0] }} | ||
/> | ||
) : ( | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.deletePolicy.confirmModal.deleteMultipleTitle" | ||
defaultMessage="Delete {count} policies?" | ||
values={{ count: policyNames.length }} | ||
/> | ||
) | ||
} | ||
onCancel={closeModal} | ||
onConfirm={deletePolicy} | ||
cancelButtonText={ | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.deletePolicy.confirmModal.cancelButtonLabel" | ||
defaultMessage="Cancel" | ||
/> | ||
} | ||
confirmButtonText={ | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.deletePolicy.confirmModal.confirmButtonLabel" | ||
defaultMessage="Delete {count, plural, one {policy} other {policies}}" | ||
values={{ count: policyNames.length }} | ||
/> | ||
} | ||
buttonColor="danger" | ||
data-test-subj="srdeletePolicyConfirmationModal" | ||
> | ||
{!isSingle ? ( | ||
<Fragment> | ||
<p> | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.deletePolicy.confirmModal.deleteMultipleListDescription" | ||
defaultMessage="You are about to delete these policies:" | ||
/> | ||
</p> | ||
<ul> | ||
{policyNames.map(name => ( | ||
<li key={name}>{name}</li> | ||
))} | ||
</ul> | ||
</Fragment> | ||
) : null} | ||
</EuiConfirmModal> | ||
</EuiOverlayMask> | ||
); | ||
}; | ||
|
||
return ( | ||
<Fragment> | ||
{children(deletePolicyPrompt)} | ||
{renderModal()} | ||
</Fragment> | ||
); | ||
}; |
127 changes: 127 additions & 0 deletions
127
x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_execute_provider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* 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, { Fragment, useRef, useState } from 'react'; | ||
import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; | ||
import { useAppDependencies } from '../index'; | ||
import { executePolicy as executePolicyRequest } from '../services/http'; | ||
|
||
interface Props { | ||
children: (executePolicy: ExecutePolicy) => React.ReactElement; | ||
} | ||
|
||
export type ExecutePolicy = (name: string, onSuccess?: OnSuccessCallback) => void; | ||
|
||
type OnSuccessCallback = () => void; | ||
|
||
export const PolicyExecuteProvider: React.FunctionComponent<Props> = ({ children }) => { | ||
const { | ||
core: { | ||
i18n, | ||
notification: { toastNotifications }, | ||
}, | ||
} = useAppDependencies(); | ||
const { FormattedMessage } = i18n; | ||
const [policyName, setPolicyName] = useState<string>(''); | ||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false); | ||
const onSuccessCallback = useRef<OnSuccessCallback | null>(null); | ||
|
||
const executePolicyPrompt: ExecutePolicy = (name, onSuccess = () => undefined) => { | ||
if (!name || !name.length) { | ||
throw new Error('No policy name specified for execution'); | ||
} | ||
setIsModalOpen(true); | ||
setPolicyName(name); | ||
onSuccessCallback.current = onSuccess; | ||
}; | ||
|
||
const closeModal = () => { | ||
setIsModalOpen(false); | ||
setPolicyName(''); | ||
}; | ||
const executePolicy = () => { | ||
executePolicyRequest(policyName).then(({ data, error }) => { | ||
const { snapshotName } = data || { snapshotName: undefined }; | ||
|
||
// Surface success notification | ||
if (snapshotName) { | ||
const successMessage = i18n.translate( | ||
'xpack.snapshotRestore.executePolicy.successNotificationTitle', | ||
{ | ||
defaultMessage: "Policy '{name}' is running", | ||
values: { name: policyName }, | ||
} | ||
); | ||
toastNotifications.addSuccess(successMessage); | ||
if (onSuccessCallback.current) { | ||
onSuccessCallback.current(); | ||
} | ||
} | ||
|
||
// Surface error notifications | ||
if (error) { | ||
const errorMessage = i18n.translate( | ||
'xpack.snapshotRestore.executePolicy.errorNotificationTitle', | ||
{ | ||
defaultMessage: "Error running policy '{name}'", | ||
values: { name: policyName }, | ||
} | ||
); | ||
toastNotifications.addDanger(errorMessage); | ||
} | ||
}); | ||
closeModal(); | ||
}; | ||
|
||
const renderModal = () => { | ||
if (!isModalOpen) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<EuiOverlayMask> | ||
<EuiConfirmModal | ||
title={ | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.executePolicy.confirmModal.executePolicyTitle" | ||
defaultMessage="Run policy '{name}'?" | ||
values={{ name: policyName }} | ||
/> | ||
} | ||
onCancel={closeModal} | ||
onConfirm={executePolicy} | ||
cancelButtonText={ | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.executePolicy.confirmModal.cancelButtonLabel" | ||
defaultMessage="Cancel" | ||
/> | ||
} | ||
confirmButtonText={ | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.executePolicy.confirmModal.confirmButtonLabel" | ||
defaultMessage="Run" | ||
/> | ||
} | ||
data-test-subj="srExecutePolicyConfirmationModal" | ||
> | ||
<p> | ||
<FormattedMessage | ||
id="xpack.snapshotRestore.executePolicy.confirmModal.executeDescription" | ||
defaultMessage="A snapshot will be taken immediately using this policy configuration." | ||
/> | ||
</p> | ||
</EuiConfirmModal> | ||
</EuiOverlayMask> | ||
); | ||
}; | ||
|
||
return ( | ||
<Fragment> | ||
{children(executePolicyPrompt)} | ||
{renderModal()} | ||
</Fragment> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.