mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
Refactor kebab modal tracking logic in delete/cancel buttons
This commit is contained in:
parent
c8a07309ee
commit
0fc6affe85
@ -1,4 +1,4 @@
|
||||
import React, { Fragment, useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
@ -51,12 +51,6 @@ function DataListToolbar({
|
||||
setKebabIsOpen(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!kebabModalIsOpen) {
|
||||
setKebabIsOpen(false);
|
||||
}
|
||||
}, [kebabModalIsOpen]);
|
||||
|
||||
return (
|
||||
<Toolbar
|
||||
id={`${qsConfig.namespace}-list-toolbar`}
|
||||
@ -98,7 +92,7 @@ function DataListToolbar({
|
||||
</ToolbarToggleGroup>
|
||||
{showExpandCollapse && (
|
||||
<ToolbarGroup>
|
||||
<Fragment>
|
||||
<>
|
||||
<ToolbarItem>
|
||||
<ExpandCollapse
|
||||
isCompact={isCompact}
|
||||
@ -106,7 +100,7 @@ function DataListToolbar({
|
||||
onExpand={onExpand}
|
||||
/>
|
||||
</ToolbarItem>
|
||||
</Fragment>
|
||||
</>
|
||||
</ToolbarGroup>
|
||||
)}
|
||||
{advancedSearchShown && (
|
||||
@ -114,7 +108,12 @@ function DataListToolbar({
|
||||
<KebabifiedProvider
|
||||
value={{
|
||||
isKebabified: true,
|
||||
onKebabModalChange: isOpen => setKebabModalIsOpen(isOpen),
|
||||
onKebabModalChange: isOpen => {
|
||||
if (kebabIsOpen && kebabModalIsOpen && !isOpen) {
|
||||
setKebabIsOpen(false);
|
||||
}
|
||||
setKebabModalIsOpen(isOpen);
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Dropdown
|
||||
@ -127,7 +126,7 @@ function DataListToolbar({
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isOpen={kebabIsOpen}
|
||||
isOpen={kebabIsOpen || kebabModalIsOpen}
|
||||
isPlain
|
||||
dropdownItems={additionalControls}
|
||||
/>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { arrayOf, func } from 'prop-types';
|
||||
import { Button, DropdownItem, Tooltip } from '@patternfly/react-core';
|
||||
import { Kebabified } from '../../contexts/Kebabified';
|
||||
import { KebabifiedContext } from '../../contexts/Kebabified';
|
||||
import AlertModal from '../AlertModal';
|
||||
import { Job } from '../../types';
|
||||
|
||||
@ -12,13 +12,21 @@ function cannotCancel(job) {
|
||||
}
|
||||
|
||||
function JobListCancelButton({ i18n, jobsToCancel, onCancel }) {
|
||||
const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const numJobsToCancel = jobsToCancel.length;
|
||||
const zeroOrOneJobSelected = numJobsToCancel < 2;
|
||||
|
||||
const handleCancel = () => {
|
||||
const handleCancelJob = () => {
|
||||
onCancel();
|
||||
setIsModalOpen(false);
|
||||
toggleModal();
|
||||
};
|
||||
|
||||
const toggleModal = () => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(!isModalOpen);
|
||||
}
|
||||
setIsModalOpen(!isModalOpen);
|
||||
};
|
||||
|
||||
const renderTooltip = () => {
|
||||
@ -61,96 +69,74 @@ function JobListCancelButton({ i18n, jobsToCancel, onCancel }) {
|
||||
);
|
||||
|
||||
return (
|
||||
<Kebabified>
|
||||
{({ isKebabified, onKebabModalChange }) => (
|
||||
<>
|
||||
{isKebabified ? (
|
||||
<DropdownItem
|
||||
key="cancel-job"
|
||||
<>
|
||||
{isKebabified ? (
|
||||
<DropdownItem
|
||||
key="cancel-job"
|
||||
isDisabled={isDisabled}
|
||||
component="button"
|
||||
onClick={toggleModal}
|
||||
>
|
||||
{cancelJobText}
|
||||
</DropdownItem>
|
||||
) : (
|
||||
<Tooltip content={renderTooltip()} position="top">
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label={cancelJobText}
|
||||
onClick={toggleModal}
|
||||
isDisabled={isDisabled}
|
||||
component="button"
|
||||
onClick={() => {
|
||||
onKebabModalChange(true);
|
||||
setIsModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{cancelJobText}
|
||||
</DropdownItem>
|
||||
) : (
|
||||
<Tooltip content={renderTooltip()} position="top">
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label={cancelJobText}
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
{cancelJobText}
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isModalOpen && (
|
||||
<AlertModal
|
||||
variant="danger"
|
||||
title={cancelJobText}
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
setIsModalOpen(false);
|
||||
}}
|
||||
actions={[
|
||||
<Button
|
||||
id="cancel-job-confirm-button"
|
||||
key="delete"
|
||||
variant="danger"
|
||||
aria-label={cancelJobText}
|
||||
onClick={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
handleCancel();
|
||||
}}
|
||||
>
|
||||
{cancelJobText}
|
||||
</Button>,
|
||||
<Button
|
||||
id="cancel-job-return-button"
|
||||
key="cancel"
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`Return`)}
|
||||
onClick={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
setIsModalOpen(false);
|
||||
}}
|
||||
>
|
||||
{i18n._(t`Return`)}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
{i18n._(
|
||||
'{numJobsToCancel, plural, one {This action will cancel the following job:} other {This action will cancel the following jobs:}}',
|
||||
{
|
||||
numJobsToCancel,
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
{jobsToCancel.map(job => (
|
||||
<span key={job.id}>
|
||||
<strong>{job.name}</strong>
|
||||
<br />
|
||||
</span>
|
||||
))}
|
||||
</AlertModal>
|
||||
)}
|
||||
</>
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Kebabified>
|
||||
{isModalOpen && (
|
||||
<AlertModal
|
||||
variant="danger"
|
||||
title={cancelJobText}
|
||||
isOpen={isModalOpen}
|
||||
onClose={toggleModal}
|
||||
actions={[
|
||||
<Button
|
||||
id="cancel-job-confirm-button"
|
||||
key="delete"
|
||||
variant="danger"
|
||||
aria-label={cancelJobText}
|
||||
onClick={handleCancelJob}
|
||||
>
|
||||
{cancelJobText}
|
||||
</Button>,
|
||||
<Button
|
||||
id="cancel-job-return-button"
|
||||
key="cancel"
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`Return`)}
|
||||
onClick={toggleModal}
|
||||
>
|
||||
{i18n._(t`Return`)}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
{i18n._(
|
||||
'{numJobsToCancel, plural, one {This action will cancel the following job:} other {This action will cancel the following jobs:}}',
|
||||
{
|
||||
numJobsToCancel,
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
{jobsToCancel.map(job => (
|
||||
<span key={job.id}>
|
||||
<strong>{job.name}</strong>
|
||||
<br />
|
||||
</span>
|
||||
))}
|
||||
</AlertModal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {
|
||||
func,
|
||||
bool,
|
||||
@ -12,7 +12,7 @@ import { Button, DropdownItem, Tooltip } from '@patternfly/react-core';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import AlertModal from '../AlertModal';
|
||||
import { Kebabified } from '../../contexts/Kebabified';
|
||||
import { KebabifiedContext } from '../../contexts/Kebabified';
|
||||
|
||||
const requireNameOrUsername = props => {
|
||||
const { name, username } = props;
|
||||
@ -59,53 +59,29 @@ function cannotDelete(item) {
|
||||
return !item.summary_fields.user_capabilities.delete;
|
||||
}
|
||||
|
||||
class ToolbarDeleteButton extends React.Component {
|
||||
static propTypes = {
|
||||
onDelete: func.isRequired,
|
||||
itemsToDelete: arrayOf(ItemToDelete).isRequired,
|
||||
pluralizedItemName: string,
|
||||
errorMessage: string,
|
||||
};
|
||||
function ToolbarDeleteButton({
|
||||
itemsToDelete,
|
||||
pluralizedItemName,
|
||||
errorMessage,
|
||||
onDelete,
|
||||
i18n,
|
||||
}) {
|
||||
const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
static defaultProps = {
|
||||
pluralizedItemName: 'Items',
|
||||
errorMessage: '',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isModalOpen: false,
|
||||
};
|
||||
|
||||
this.handleConfirmDelete = this.handleConfirmDelete.bind(this);
|
||||
this.handleCancelDelete = this.handleCancelDelete.bind(this);
|
||||
this.handleDelete = this.handleDelete.bind(this);
|
||||
}
|
||||
|
||||
handleConfirmDelete() {
|
||||
this.setState({ isModalOpen: true });
|
||||
}
|
||||
|
||||
handleCancelDelete() {
|
||||
this.setState({ isModalOpen: false });
|
||||
}
|
||||
|
||||
handleDelete() {
|
||||
const { onDelete } = this.props;
|
||||
const handleDelete = () => {
|
||||
onDelete();
|
||||
this.setState({ isModalOpen: false });
|
||||
}
|
||||
toggleModal();
|
||||
};
|
||||
|
||||
renderTooltip() {
|
||||
const {
|
||||
itemsToDelete,
|
||||
pluralizedItemName,
|
||||
errorMessage,
|
||||
i18n,
|
||||
} = this.props;
|
||||
const toggleModal = () => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(!isModalOpen);
|
||||
}
|
||||
setIsModalOpen(!isModalOpen);
|
||||
};
|
||||
|
||||
const renderTooltip = () => {
|
||||
const itemsUnableToDelete = itemsToDelete
|
||||
.filter(cannotDelete)
|
||||
.map(item => item.name)
|
||||
@ -125,103 +101,89 @@ class ToolbarDeleteButton extends React.Component {
|
||||
return i18n._(t`Delete`);
|
||||
}
|
||||
return i18n._(t`Select a row to delete`);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { itemsToDelete, pluralizedItemName, i18n } = this.props;
|
||||
const { isModalOpen } = this.state;
|
||||
const modalTitle = i18n._(t`Delete ${pluralizedItemName}?`);
|
||||
const modalTitle = i18n._(t`Delete ${pluralizedItemName}?`);
|
||||
|
||||
const isDisabled =
|
||||
itemsToDelete.length === 0 || itemsToDelete.some(cannotDelete);
|
||||
const isDisabled =
|
||||
itemsToDelete.length === 0 || itemsToDelete.some(cannotDelete);
|
||||
|
||||
// NOTE: Once PF supports tooltips on disabled elements,
|
||||
// we can delete the extra <div> around the <DeleteButton> below.
|
||||
// See: https://github.com/patternfly/patternfly-react/issues/1894
|
||||
return (
|
||||
<Kebabified>
|
||||
{({ isKebabified, onKebabModalChange }) => (
|
||||
<Fragment>
|
||||
{isKebabified ? (
|
||||
<DropdownItem
|
||||
key="add"
|
||||
isDisabled={isDisabled}
|
||||
component="button"
|
||||
onClick={() => {
|
||||
onKebabModalChange(true);
|
||||
this.handleConfirmDelete();
|
||||
}}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</DropdownItem>
|
||||
) : (
|
||||
<Tooltip content={this.renderTooltip()} position="top">
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`Delete`)}
|
||||
onClick={this.handleConfirmDelete}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isModalOpen && (
|
||||
<AlertModal
|
||||
variant="danger"
|
||||
title={modalTitle}
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
this.handleCancelDelete();
|
||||
}}
|
||||
actions={[
|
||||
<Button
|
||||
key="delete"
|
||||
variant="danger"
|
||||
aria-label={i18n._(t`confirm delete`)}
|
||||
onClick={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
this.handleDelete();
|
||||
}}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</Button>,
|
||||
<Button
|
||||
key="cancel"
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`cancel delete`)}
|
||||
onClick={() => {
|
||||
if (isKebabified) {
|
||||
onKebabModalChange(false);
|
||||
}
|
||||
this.handleCancelDelete();
|
||||
}}
|
||||
>
|
||||
{i18n._(t`Cancel`)}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>{i18n._(t`This action will delete the following:`)}</div>
|
||||
{itemsToDelete.map(item => (
|
||||
<span key={item.id}>
|
||||
<strong>{item.name || item.username}</strong>
|
||||
<br />
|
||||
</span>
|
||||
))}
|
||||
</AlertModal>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Kebabified>
|
||||
);
|
||||
}
|
||||
// NOTE: Once PF supports tooltips on disabled elements,
|
||||
// we can delete the extra <div> around the <DeleteButton> below.
|
||||
// See: https://github.com/patternfly/patternfly-react/issues/1894
|
||||
return (
|
||||
<>
|
||||
{isKebabified ? (
|
||||
<DropdownItem
|
||||
key="add"
|
||||
isDisabled={isDisabled}
|
||||
component="button"
|
||||
onClick={toggleModal}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</DropdownItem>
|
||||
) : (
|
||||
<Tooltip content={renderTooltip()} position="top">
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`Delete`)}
|
||||
onClick={toggleModal}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isModalOpen && (
|
||||
<AlertModal
|
||||
variant="danger"
|
||||
title={modalTitle}
|
||||
isOpen={isModalOpen}
|
||||
onClose={toggleModal}
|
||||
actions={[
|
||||
<Button
|
||||
key="delete"
|
||||
variant="danger"
|
||||
aria-label={i18n._(t`confirm delete`)}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
{i18n._(t`Delete`)}
|
||||
</Button>,
|
||||
<Button
|
||||
key="cancel"
|
||||
variant="secondary"
|
||||
aria-label={i18n._(t`cancel delete`)}
|
||||
onClick={toggleModal}
|
||||
>
|
||||
{i18n._(t`Cancel`)}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>{i18n._(t`This action will delete the following:`)}</div>
|
||||
{itemsToDelete.map(item => (
|
||||
<span key={item.id}>
|
||||
<strong>{item.name || item.username}</strong>
|
||||
<br />
|
||||
</span>
|
||||
))}
|
||||
</AlertModal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ToolbarDeleteButton.propTypes = {
|
||||
onDelete: func.isRequired,
|
||||
itemsToDelete: arrayOf(ItemToDelete).isRequired,
|
||||
pluralizedItemName: string,
|
||||
errorMessage: string,
|
||||
};
|
||||
|
||||
ToolbarDeleteButton.defaultProps = {
|
||||
pluralizedItemName: 'Items',
|
||||
errorMessage: '',
|
||||
};
|
||||
|
||||
export default withI18n()(ToolbarDeleteButton);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user