From b5d85151e60a78f0d332fcdeece1fb5ec2673c69 Mon Sep 17 00:00:00 2001 From: "andy.lee" Date: Tue, 9 Jul 2024 16:40:03 +0800 Subject: [PATCH] allow input secret/secretNamespace when restore bbi Signed-off-by: andy.lee --- .eslintrc | 1 - src/models/backingImage.js | 30 ++++++-- .../backingImage/BackingImageBulkActions.js | 2 +- .../RestoreBackupBackingImageModal.js | 76 +++++++++++++++++++ src/routes/backingImage/index.js | 33 +++++++- src/routes/systemBackups/index.js | 2 +- src/services/backingImage.js | 2 +- src/utils/dataDependency.js | 6 +- src/utils/websocket.js | 7 -- 9 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 src/routes/backingImage/RestoreBackupBackingImageModal.js diff --git a/.eslintrc b/.eslintrc index fd32d852..5e3c107a 100755 --- a/.eslintrc +++ b/.eslintrc @@ -33,7 +33,6 @@ "linebreak-style": [0 ,"error", "windows"], "react/no-access-state-in-setstate": 0, "react/jsx-first-prop-new-line": 0, - "react/jsx-props-no-spreading": 0, "import/prefer-default-export": 0, "react/jsx-filename-extension": 0, "react/jsx-props-no-spreading": 0, diff --git a/src/models/backingImage.js b/src/models/backingImage.js index 50445283..ebee14f3 100644 --- a/src/models/backingImage.js +++ b/src/models/backingImage.js @@ -3,7 +3,7 @@ import { deleteBackingImage, deleteBackupBackingImage, execAction, - queryBbiList, + queryBackupBackingImageList, query, deleteDisksOnBackingImage, uploadChunk, @@ -27,6 +27,7 @@ export default { data: [], bbiData: [], // backupBackingImage data selected: {}, + bbiSelected: {}, selectedRows: [], nodeTags: [], diskTags: [], @@ -37,6 +38,7 @@ export default { createBackingImageModalKey: Math.random(), diskStateMapDetailModalVisible: false, diskStateMapDetailModalKey: Math.random(), + restoreBackupBackingImageModalVisible: false, diskStateMapDeleteDisabled: true, diskStateMapDeleteLoading: false, selectedDiskStateMapRows: [], @@ -73,7 +75,7 @@ export default { // eslint-disable-next-line no-unused-vars _payload, }, { call, put }) { - const resp = yield call(queryBbiList) + const resp = yield call(queryBackupBackingImageList) if (resp && resp.data) { const bbiData = resp.data sortByCreatedTime(bbiData) @@ -148,11 +150,17 @@ export default { *restoreBackingImage({ payload, }, { call, put }) { - const resp = yield call(execAction, payload.actions.backupBackingImageRestore) - if (resp && resp.status === 200) { - message.success(`Successfully restore ${payload.name} backing image`) + yield put({ type: 'hideRestoreBackingImageModal' }) + const restoreUrl = payload.item?.actions?.backupBackingImageRestore + if (restoreUrl) { + const resp = yield call(execAction, restoreUrl, payload.params) + if (resp && resp.status === 200) { + message.success(`Successfully restore ${payload.item.name} backing image`) + } + yield put({ type: 'query' }) + } else { + message.error('Missing restore backup backing image url') } - yield put({ type: 'query' }) }, *deleteBackupBackingImage({ payload, @@ -186,7 +194,7 @@ export default { if (payload && payload.length > 0) { yield payload.map(item => call(deleteBackupBackingImage, item)) } - yield delay(2000) + yield delay(3000) yield put({ type: 'queryBackupBackingImage' }) }, *bulkBackup({ @@ -200,7 +208,7 @@ export default { } } } - yield delay(4000) + yield delay(3000) yield put({ type: 'queryBackupBackingImage' }) }, *bulkDownload({ @@ -321,6 +329,9 @@ export default { } } }, + showRestoreBackingImage(state, action) { + return { ...state, ...action.payload, restoreBackupBackingImageModalVisible: true } + }, showCreateBackingImageModal(state, action) { return { ...state, ...action.payload, createBackingImageModalVisible: true, createBackingImageModalKey: Math.random() } }, @@ -331,6 +342,9 @@ export default { selected: action.payload, } }, + hideRestoreBackingImageModal(state, action) { + return { ...state, ...action.payload, restoreBackupBackingImageModalVisible: false, bbiSelected: {} } + }, hideCreateBackingImageModal(state) { return { ...state, createBackingImageModalVisible: false } }, diff --git a/src/routes/backingImage/BackingImageBulkActions.js b/src/routes/backingImage/BackingImageBulkActions.js index 8c855a97..da40690e 100644 --- a/src/routes/backingImage/BackingImageBulkActions.js +++ b/src/routes/backingImage/BackingImageBulkActions.js @@ -90,7 +90,7 @@ function bulkActions({ selectedRows, deleteBackingImages, downloadSelectedBackin const allActions = [ { key: 'delete', name: 'Delete', disabled() { return selectedRows.length === 0 } }, { key: 'download', name: 'Download', disabled() { return (selectedRows.length === 0 || selectedRows.every(row => !hasReadyBackingDisk(row))) } }, - { key: 'backup', name: 'Backup', disabled() { return selectedRows.length === 0 } }, + { key: 'backup', name: 'Backup', disabled() { return selectedRows.length === 0 || selectedRows.every(row => !hasReadyBackingDisk(row)) } }, ] return ( diff --git a/src/routes/backingImage/RestoreBackupBackingImageModal.js b/src/routes/backingImage/RestoreBackupBackingImageModal.js new file mode 100644 index 00000000..1c231952 --- /dev/null +++ b/src/routes/backingImage/RestoreBackupBackingImageModal.js @@ -0,0 +1,76 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Form, Input } from 'antd' +import { ModalBlur } from '../../components' + +const FormItem = Form.Item + +const formItemLayout = { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 12, + }, +} + +const modal = ({ + item, + visible, + onOk, + onCancel, + form: { + getFieldDecorator, + validateFields, + getFieldValue, + }, +}) => { + function handleOk() { + validateFields((errors) => { + if (errors) { + return + } + const data = { + secret: getFieldValue('secret') || '', + secretNamespace: getFieldValue('secretNamespace') || '', + } + onOk(item, data) + }) + } + + const modalOpts = { + title: `Restore ${item.name} Backup Backing Image`, + visible, + onCancel, + onOk: handleOk, + } + if (!item) { + return null + } + return ( + +
+ + {getFieldDecorator('secret', { + initialValue: '', + })()} + + + {getFieldDecorator('secretNamespace', { + initialValue: '', + })()} + +
+
+ ) +} + +modal.propTypes = { + form: PropTypes.object.isRequired, + visible: PropTypes.bool, + onCancel: PropTypes.func, + item: PropTypes.object, + onOk: PropTypes.func, +} + +export default Form.create()(modal) diff --git a/src/routes/backingImage/index.js b/src/routes/backingImage/index.js index c01538e2..2a4b5ef0 100644 --- a/src/routes/backingImage/index.js +++ b/src/routes/backingImage/index.js @@ -10,6 +10,7 @@ import { Filter } from '../../components/index' import BackingImageBulkActions from './BackingImageBulkActions' import UpdateMinCopiesCount from './UpdateMinCopiesCount' import BackupBackingImageBulkActions from './BackupBackingImageBulkActions' +import RestoreBackupBackingImageModal from './RestoreBackupBackingImageModal' import style from './BackingImage.less' const filterBackingImage = (data, field, value) => { @@ -21,9 +22,11 @@ const filterBackingImage = (data, field, value) => { case 'name': case 'uuid': case 'minNumberOfCopies': + backingImages = backingImages.filter((image) => (value ? image[field].toString().includes(value.toString().trim()) : true)) + break case 'diskSelector': case 'nodeSelector': - backingImages = backingImages.filter((image) => (value ? image[field].toString().includes(value.toString().trim()) : true)) + backingImages = backingImages.filter((image) => (value ? image[field]?.toString().includes(value.trim()) || false : true)) break case 'sourceType': backingImages = backingImages.filter((image) => (value ? image.sourceType === value.trim() : true)) @@ -132,10 +135,12 @@ class BackingImage extends React.Component { bbiSearchField, bbiSearchValue, selected, + bbiSelected, nodeTags, diskTags, tagsLoading, minCopiesCountModalVisible, + restoreBackupBackingImageModalVisible, createBackingImageModalVisible, createBackingImageModalKey, diskStateMapDetailModalVisible, @@ -169,8 +174,10 @@ class BackingImage extends React.Component { }, restoreBackingImage(record) { dispatch({ - type: 'backingImage/restoreBackingImage', - payload: record, + type: 'backingImage/showRestoreBackingImage', + payload: { + bbiSelected: record, + }, }) }, rowSelection: { @@ -286,6 +293,25 @@ class BackingImage extends React.Component { }, } + const restoreBBiModalProps = { + item: bbiSelected, + visible: restoreBackupBackingImageModalVisible, + onOk(item, params) { + dispatch({ + type: 'backingImage/restoreBackingImage', + payload: { + item, + params, + }, + }) + }, + onCancel() { + dispatch({ + type: 'backingImage/hideRestoreBackingImageModal', + }) + }, + } + const diskStateMapDetailModalProps = { selected, backingImages, @@ -475,6 +501,7 @@ class BackingImage extends React.Component { Uploading )} + { restoreBackupBackingImageModalVisible && } { minCopiesCountModalVisible && } { createBackingImageModalVisible ? : ''} { diskStateMapDetailModalVisible ? : ''} diff --git a/src/routes/systemBackups/index.js b/src/routes/systemBackups/index.js index 7fc88d33..a4fb028e 100644 --- a/src/routes/systemBackups/index.js +++ b/src/routes/systemBackups/index.js @@ -238,7 +238,7 @@ class SystemBackups extends React.Component {
- + System Restore
diff --git a/src/services/backingImage.js b/src/services/backingImage.js index 8ca847b7..fb50f731 100644 --- a/src/services/backingImage.js +++ b/src/services/backingImage.js @@ -17,7 +17,7 @@ export async function execAction(url, params) { }) } -export async function queryBbiList() { +export async function queryBackupBackingImageList() { return request({ url: '/v1/backupbackingimages', method: 'get', diff --git a/src/utils/dataDependency.js b/src/utils/dataDependency.js index 5b8fb3bf..714d355f 100644 --- a/src/utils/dataDependency.js +++ b/src/utils/dataDependency.js @@ -76,9 +76,6 @@ const dependency = { }, { ns: 'setting', key: 'settings', - }, { - ns: 'backup', - key: 'backup', }], }, settings: { @@ -170,7 +167,7 @@ const httpDataDependency = { '/volume': ['volume', 'host', 'setting', 'backingImage', 'engineimage', 'recurringJob', 'backup'], '/engineimage': ['engineimage'], '/recurringJob': ['recurringJob'], - '/backingImage': ['volume', 'backingImage', 'setting', 'backup'], + '/backingImage': ['volume', 'backingImage', 'setting'], '/setting': ['setting'], '/backup': ['host', 'setting', 'backingImage', 'backup'], '/instanceManager': ['volume', 'instanceManager'], @@ -186,7 +183,6 @@ export function getDataDependency(pathName) { } return false }) - // console.log('🚀 ~ keys ~ keys:', keys) if (keys && keys.length === 1) { let modal = dependency[keys[0]] diff --git a/src/utils/websocket.js b/src/utils/websocket.js index 12a9c5e8..36b926ec 100644 --- a/src/utils/websocket.js +++ b/src/utils/websocket.js @@ -20,7 +20,6 @@ export function constructWebsocketURL(type, period) { } export function wsChanges(dispatch, type, period, ns, search) { - console.log('🚀 ~ wsChanges ~ type:', type) const url = constructWebsocketURL(type, period) const options = { timeout: 4000, @@ -77,9 +76,6 @@ export function wsChanges(dispatch, type, period, ns, search) { }, 30000) // TODO: can refactor this to use a single event listener and dispatch to the correct action rws.addEventListener('message', (msg) => { - if (ns === 'backingImage') { - console.log('message rws.addEventListener ~ type =', backupType, ' msg:', JSON.parse(msg.data)) - } recentWrite = true if (ns === 'backup') { if (backupType === 'backupvolumes') { @@ -95,16 +91,13 @@ export function wsChanges(dispatch, type, period, ns, search) { }) } } else if (ns === 'backingImage') { - console.log('message data ns:', ns, 'backupType:', backupType) if (backupType === 'backingimages') { - console.log('message backupType === backingimages call ns/updateBackground', JSON.parse(msg.data).data) dispatch({ type: `${ns}/updateBackground`, payload: JSON.parse(msg.data), }) } if (backupType === 'backupbackingimages') { - console.log('message backupType === backupbackingimages call ns/updateBackgroundBBi', JSON.parse(msg.data).data) dispatch({ type: `${ns}/updateBackgroundBBi`, payload: JSON.parse(msg.data),