-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Yi-Ya Chen <[email protected]>
- Loading branch information
1 parent
ddfa9dd
commit 21c4758
Showing
4 changed files
with
211 additions
and
114 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
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 |
---|---|---|
@@ -1,139 +1,193 @@ | ||
import React from 'react' | ||
import React, { useState } from 'react' | ||
import PropTypes from 'prop-types' | ||
import { Button, Modal } from 'antd' | ||
import { Form, Button, Modal, Select, Icon } from 'antd' | ||
import { hasReadyBackingDisk, diskStatusColorMap } from '../../utils/status' | ||
import styles from './BackingImageBulkActions.less' | ||
|
||
const confirm = Modal.confirm | ||
function BulkActions({ | ||
selectedRows, | ||
backupProps, | ||
deleteBackingImages, | ||
downloadSelectedBackingImages, | ||
backupSelectedBackingImages, | ||
backupTargets = [], | ||
form = {}, | ||
}) { | ||
const [isBackupModalVisible, setIsBackupModalVisible] = useState(false) | ||
|
||
|
||
function bulkActions({ selectedRows, backupProps, deleteBackingImages, downloadSelectedBackingImages, backupSelectedBackingImages }) { | ||
const { getFieldDecorator, getFieldValue } = form | ||
const { backupTargetAvailable } = backupProps | ||
const readyColor = diskStatusColorMap.ready | ||
const readyTextStyle = { | ||
display: 'inline-block', | ||
width: 'max-content', | ||
padding: '0 4px', | ||
color: '#27AE5F', | ||
border: `1px solid ${readyColor.color}`, | ||
backgroundColor: readyColor.bg, | ||
textTransform: 'capitalize', | ||
} | ||
const getImageLabel = selectedRows.length === 1 ? 'image' : 'images' | ||
const readyImages = selectedRows.filter((row) => hasReadyBackingDisk(row)) | ||
|
||
const handleDelete = () => { | ||
const title = ( | ||
<> | ||
<p> | ||
Are you sure you want to delete the following {selectedRows.length} backing {getImageLabel}? | ||
</p> | ||
<ul> | ||
{selectedRows.map((item) => ( | ||
<li key={item.name}>{item.name}</li> | ||
))} | ||
</ul> | ||
</> | ||
) | ||
Modal.confirm({ | ||
width: 'fit-content', | ||
okText: 'Delete', | ||
okType: 'danger', | ||
title, | ||
content: null, | ||
onOk: () => deleteBackingImages(selectedRows), | ||
}) | ||
} | ||
|
||
const handleDownload = () => { | ||
const downloadableImages = selectedRows.filter((row) => hasReadyBackingDisk(row)) | ||
|
||
const title = ( | ||
<> | ||
<p> | ||
The following backing {getImageLabel} with <strong style={readyTextStyle}>Ready</strong> status disk will be downloaded. | ||
</p> | ||
<ul> | ||
{downloadableImages.map((item) => ( | ||
<li key={item.name}>{item.name}</li> | ||
))} | ||
</ul> | ||
<p> | ||
Note: You need to allow <strong>Automatic Downloads</strong> in browser settings to download multiple files at once. | ||
</p> | ||
</> | ||
) | ||
Modal.confirm({ | ||
width: 'fit-content', | ||
okText: 'Download', | ||
title, | ||
content: null, | ||
onOk: () => downloadSelectedBackingImages(downloadableImages), | ||
}) | ||
} | ||
|
||
const handleBackup = () => { | ||
setIsBackupModalVisible(true) | ||
} | ||
|
||
const handleBackupOk = () => { | ||
const backupTarget = backupTargets.find((bkTarget) => bkTarget.name === getFieldValue('backupTargetName')) | ||
const backupImages = readyImages.map((backingImage) => ({ | ||
...backingImage, | ||
backingImageName: backingImage.name, | ||
backupTargetName: backupTarget.name, | ||
backupTargetURL: backupTarget.backupTargetURL, | ||
})) | ||
|
||
backupSelectedBackingImages(backupImages) | ||
setIsBackupModalVisible(false) | ||
} | ||
|
||
const handleClick = (action) => { | ||
const count = selectedRows.length | ||
switch (action) { | ||
case 'delete': | ||
confirm({ | ||
width: 'fit-content', | ||
okText: 'Delete', | ||
okType: 'danger', | ||
title: (<> | ||
<p>Are you sure to delete below {count} backing {count === 1 ? 'image' : 'images' } ?</p> | ||
<ul> | ||
{selectedRows.map(item => <li>{item.name}</li>)}, | ||
</ul> | ||
</>), | ||
onOk() { | ||
deleteBackingImages(selectedRows) | ||
}, | ||
}) | ||
break | ||
case 'download': { | ||
const downloadableImages = selectedRows.filter(row => hasReadyBackingDisk(row)) | ||
const readyColor = diskStatusColorMap.ready | ||
const readyTextStyle = { | ||
display: 'inline-block', | ||
width: 'max-content', | ||
padding: '0 4px', | ||
marginRight: '5px', | ||
color: '#27AE5F', | ||
border: `1px solid ${readyColor.color}`, | ||
backgroundColor: readyColor.bg, | ||
textTransform: 'capitalize', | ||
} | ||
confirm({ | ||
okText: 'Download', | ||
width: 'fit-content', | ||
title: (<> | ||
<p>Below backing {count === 1 ? 'image' : 'images' } with <strong style={readyTextStyle}>Ready</strong> status disk will be downloaded</p> | ||
<ul> | ||
{downloadableImages.map(item => <li>{item.name}</li>)} | ||
</ul> | ||
<p>Note. You need allow <strong>Automatic Downloads</strong> permission<br />in browser settings to download multiple files at once.</p> | ||
</>), | ||
onOk() { | ||
downloadSelectedBackingImages(downloadableImages) | ||
}, | ||
}) | ||
break | ||
} | ||
case 'backup': { | ||
const backupImages = selectedRows.filter(row => hasReadyBackingDisk(row)) | ||
const readyColor = diskStatusColorMap.ready | ||
const readyTextStyle = { | ||
display: 'inline-block', | ||
width: 'max-content', | ||
padding: '0 4px', | ||
marginRight: '5px', | ||
color: '#27AE5F', | ||
border: `1px solid ${readyColor.color}`, | ||
backgroundColor: readyColor.bg, | ||
textTransform: 'capitalize', | ||
} | ||
confirm({ | ||
okText: 'Backup', | ||
width: 'fit-content', | ||
title: (<> | ||
<p>Are you sure to backup below <strong style={readyTextStyle}>Ready</strong> status backing {count === 1 ? 'image' : 'images'} ?</p> | ||
<ul> | ||
{backupImages.map(item => <li key={item.name}>{item.name}</li>)} | ||
</ul> | ||
</>), | ||
onOk() { | ||
backupSelectedBackingImages(backupImages) | ||
}, | ||
}) | ||
break | ||
} | ||
default: | ||
} | ||
const handleBackupCancel = () => { | ||
setIsBackupModalVisible(false) | ||
} | ||
|
||
const allActions = [ | ||
{ | ||
key: 'delete', | ||
name: 'Delete', | ||
disabled() { return selectedRows.length === 0 } | ||
disabled: () => selectedRows.length === 0, | ||
onClick: handleDelete, | ||
}, | ||
{ | ||
key: 'download', | ||
name: 'Download', | ||
disabled() { | ||
return selectedRows.length === 0 | ||
|| selectedRows.every(row => !hasReadyBackingDisk(row)) | ||
|| selectedRows.some(row => row.dataEngine === 'v2') | ||
} | ||
disabled: () => selectedRows.length === 0 | ||
|| readyImages.length === 0 | ||
|| selectedRows.some((row) => row.dataEngine === 'v2'), | ||
onClick: handleDownload, | ||
}, | ||
{ | ||
key: 'backup', | ||
name: 'Back Up', | ||
disabled() { | ||
return selectedRows.length === 0 | ||
|| backupTargetAvailable === false | ||
|| selectedRows.every(row => !hasReadyBackingDisk(row)) | ||
} | ||
name: 'Backup', | ||
disabled: () => selectedRows.length === 0 | ||
|| readyImages.length === 0 | ||
|| !backupTargetAvailable, | ||
onClick: handleBackup, | ||
}, | ||
] | ||
|
||
return ( | ||
<div style={{ display: 'flex' }}> | ||
{ allActions.map(item => { | ||
return ( | ||
<div key={item.key} style={{ marginRight: '10px' }}> | ||
<Button size="large" type="primary" disabled={item.disabled()} onClick={() => handleClick(item.key)}>{ item.name }</Button> | ||
</div> | ||
) | ||
}) } | ||
</div> | ||
<> | ||
<div style={{ display: 'flex' }}> | ||
{allActions.map(({ key, name, disabled, onClick }) => ( | ||
<Button | ||
key={key} | ||
size="large" | ||
type="primary" | ||
disabled={disabled()} | ||
onClick={onClick} | ||
className={styles.bulkActionBtns} | ||
> | ||
{name} | ||
</Button> | ||
))} | ||
</div> | ||
<Modal | ||
className={styles.backupModal} | ||
closable={false} | ||
width="fit-content" | ||
okText="Backup" | ||
visible={isBackupModalVisible} | ||
onOk={handleBackupOk} | ||
onCancel={handleBackupCancel} | ||
> | ||
<Icon className={styles.questionCircleIcon} type="question-circle" /> | ||
<Form className={styles.backupForm}> | ||
<p> | ||
Are you sure you want to backup the following <strong style={readyTextStyle}>Ready</strong> status backing {readyImages.length === 1 ? 'image' : 'images'}? | ||
</p> | ||
<ul>{readyImages.map((item) => <li key={item.name}>{item.name}</li>)}</ul> | ||
<Form.Item label="Backup Target"> | ||
{getFieldDecorator('backupTargetName', { | ||
initialValue: backupTargets.find((bk) => bk.name === 'default')?.name || '', | ||
})( | ||
<Select> | ||
{backupTargets.map((bkTarget) => ( | ||
<Select.Option | ||
key={bkTarget.name} | ||
disabled={!bkTarget.available} | ||
value={bkTarget.name} | ||
> | ||
{bkTarget.name} | ||
</Select.Option> | ||
))} | ||
</Select> | ||
)} | ||
</Form.Item> | ||
</Form> | ||
</Modal> | ||
</> | ||
) | ||
} | ||
|
||
bulkActions.propTypes = { | ||
selectedRows: PropTypes.array, | ||
deleteBackingImages: PropTypes.func, | ||
downloadSelectedBackingImages: PropTypes.func, | ||
backupSelectedBackingImages: PropTypes.func, | ||
backupProps: PropTypes.object, | ||
BulkActions.propTypes = { | ||
selectedRows: PropTypes.array.isRequired, | ||
deleteBackingImages: PropTypes.func.isRequired, | ||
downloadSelectedBackingImages: PropTypes.func.isRequired, | ||
backupSelectedBackingImages: PropTypes.func.isRequired, | ||
backupProps: PropTypes.object.isRequired, | ||
backupTargets: PropTypes.array.isRequired, | ||
form: PropTypes.object.isRequired, | ||
} | ||
|
||
export default bulkActions | ||
export default Form.create()(BulkActions) |
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,41 @@ | ||
.bulkActionBtns { | ||
margin-right: 10px; | ||
} | ||
|
||
.backupModal { | ||
display: flex; | ||
|
||
.questionCircleIcon { | ||
margin-right: 16px; | ||
font-size: 22px; | ||
color: #faad14; | ||
} | ||
|
||
.backupForm { | ||
color: #000000d9; | ||
font-weight: 500; | ||
font-size: 17px; | ||
line-height: 1.4; | ||
} | ||
|
||
:global { | ||
.ant-modal-body { | ||
display: flex; | ||
padding: 32px 32px 0; | ||
|
||
.ant-form-item { | ||
display: flex; | ||
margin-bottom: 0; | ||
} | ||
|
||
.ant-col.ant-form-item-control-wrapper { | ||
flex: 1; | ||
} | ||
} | ||
|
||
.ant-modal-footer { | ||
padding: 24px 32px; | ||
border-top: 0; | ||
} | ||
} | ||
} |
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