this.remove(k)}
- />) : null}
+
+
+ {getFieldDecorator(`key[${k}]`, {
+ validateTrigger: ['onChange', 'onBlur'],
+ rules: [
+ {
+ required: true,
+ whitespace: true,
+ message: 'key is required',
+ },
+ ],
+ })()}
+
+
+ {getFieldDecorator(`value[${k}]`, {
+ validateTrigger: ['onChange', 'onBlur'],
+ rules: [
+ {
+ required: true,
+ whitespace: true,
+ message: 'value is required',
+ },
+ ],
+ })()}
+ {keys.length > 0 ? (
+ this.remove(k)}
+ />) : null}
))
return (
+
+ {formItems}
)
}
diff --git a/src/models/backupTarget.js b/src/models/backupTarget.js
index 438ad98cf..2a8e2c7b5 100644
--- a/src/models/backupTarget.js
+++ b/src/models/backupTarget.js
@@ -1,6 +1,5 @@
import { queryBackupTarget, createBackupTarget, deleteBackupTarget, updateBackupTarget } from '../services/backupTarget'
import { message } from 'antd'
-// import { delay } from 'dva/saga'
import { wsChanges, updateState } from '../utils/websocket'
import queryString from 'query-string'
import { enableQueryData } from '../utils/dataDependency'
@@ -12,14 +11,6 @@ export default {
data: [],
resourceType: 'backupTarget',
selectedRows: [],
- // createBackingImageModalVisible: false,
- // createBackingImageModalKey: Math.random(),
- // diskStateMapDetailModalVisible: false,
- // diskStateMapDetailModalKey: Math.random(),
- // diskStateMapDeleteDisabled: true,
- // diskStateMapDeleteLoading: false,
- // selectedDiskStateMapRows: [],
- // selectedDiskStateMapRowKeys: [],
socketStatus: 'closed',
},
subscriptions: {
@@ -39,8 +30,6 @@ export default {
payload,
}, { call, put }) {
const data = yield call(queryBackupTarget, payload)
- console.log('🚀 ~ data:', data)
- console.log('🚀 ~ backupTarget query data:', data)
if (payload && payload.field && payload.keyword && data.data) {
data.data = data.data.filter(item => item[payload.field] && item[payload.field].indexOf(payload.keyword.trim()) > -1)
}
@@ -54,7 +43,6 @@ export default {
payload,
}, { call, put }) {
const resp = yield call(createBackupTarget, payload)
- // console.log('🚀 ~ create resp:', resp)
if (resp && resp.status === 200) {
message.success(`Successfully create backup target ${payload.name}.`)
}
@@ -69,7 +57,6 @@ export default {
*edit({
payload,
}, { call, put }) {
- // console.log('🚀 ~edit payload:', payload)
yield call(updateBackupTarget, payload)
yield put({ type: 'query' })
},
@@ -85,7 +72,6 @@ export default {
payload,
}, { select }) {
let ws = yield select(state => state.backupTarget.ws)
- console.log('🚀 ~ backupTarget startWS ws:', ws)
if (ws) {
ws.open()
} else {
@@ -118,38 +104,6 @@ export default {
updateBackground(state, action) {
return updateState(state, action)
},
- // showCreateBackingImageModal(state, action) {
- // return { ...state, ...action.payload, createBackingImageModalVisible: true, createBackingImageModalKey: Math.random() }
- // },
- // hideCreateBackingImageModal(state) {
- // return { ...state, createBackingImageModalVisible: false }
- // },
- // showDiskStateMapDetailModal(state, action) {
- // return {
- // ...state,
- // selected: action.payload.record,
- // diskStateMapDetailModalVisible: true,
- // diskStateMapDetailModalKey: Math.random(),
- // }
- // },
- // hideDiskStateMapDetailModal(state) {
- // return { ...state, diskStateMapDetailModalVisible: false, diskStateMapDetailModalKey: Math.random() }
- // },
- // disableDiskStateMapDelete(state) {
- // return { ...state, diskStateMapDeleteDisabled: true }
- // },
- // enableDiskStateMapDelete(state) {
- // return { ...state, diskStateMapDeleteDisabled: false }
- // },
- // disableDiskStateMapDeleteLoading(state) {
- // return { ...state, diskStateMapDeleteLoading: false }
- // },
- // enableDiskStateMapDeleteLoading(state) {
- // return { ...state, diskStateMapDeleteLoading: true }
- // },
- changeDiskStateMapSelection(state, action) {
- return { ...state, ...action.payload }
- },
updateSocketStatus(state, action) {
return { ...state, socketStatus: action.payload }
},
diff --git a/src/models/snapshot.js b/src/models/snapshot.js
index a1d74c102..c26c6495b 100644
--- a/src/models/snapshot.js
+++ b/src/models/snapshot.js
@@ -204,9 +204,9 @@ export default (namespace) => {
yield put({ type: 'setLoading', payload: true })
const snapshot = yield call(execAction, payload.snapshotCreateUrl, {})
if (Object.getOwnPropertyNames(payload.labels).length === 0) {
- yield call(execAction, payload.snapshotBackupUrl, { name: snapshot.name })
+ yield call(execAction, payload.snapshotBackupUrl, { name: snapshot.name, backupTargetName: payload.backupTargetName })
} else {
- yield call(execAction, payload.snapshotBackupUrl, { name: snapshot.name, labels: payload.labels, backupTargetName: 'andy-minio-backupstore' })
+ yield call(execAction, payload.snapshotBackupUrl, { name: snapshot.name, labels: payload.labels, backupTargetName: payload.backupTargetName })
}
yield put({ type: 'querySnapShot', payload: { url: payload.querySnapShotUrl } })
yield put({ type: 'setLoading', payload: false })
@@ -216,9 +216,9 @@ export default (namespace) => {
}, { call, put }) {
yield put({ type: 'setLoading', payload: true })
if (Object.getOwnPropertyNames(payload.labels).length === 0) {
- yield call(execAction, payload.snapshotBackupUrl, { name: payload.snapshotName })
+ yield call(execAction, payload.snapshotBackupUrl, { name: payload.snapshotName, backupTargetName: payload.backupTargetName })
} else {
- yield call(execAction, payload.snapshotBackupUrl, { name: payload.snapshotName, labels: payload.labels })
+ yield call(execAction, payload.snapshotBackupUrl, { name: payload.snapshotName, labels: payload.labels, backupTargetName: payload.backupTargetName })
}
yield put({ type: 'querySnapShot', payload: { url: payload.querySnapShotUrl } })
yield put({ type: 'setLoading', payload: false })
diff --git a/src/routes/backupTarget/BackupTargetList.js b/src/routes/backupTarget/BackupTargetList.js
index 81f8a3d86..2463a7aa0 100644
--- a/src/routes/backupTarget/BackupTargetList.js
+++ b/src/routes/backupTarget/BackupTargetList.js
@@ -69,7 +69,7 @@ function list({ loading, dataSource, deleteBackupTarget, editBackupTarget, rowSe
sorter: (a, b) => a.default - b.default,
render: (text) => {
return (
- {text.toString().firstUpperCase()}
+ {text.toString().firstUpperCase()}
)
},
}, {
@@ -81,7 +81,7 @@ function list({ loading, dataSource, deleteBackupTarget, editBackupTarget, rowSe
render: (text) => {
return (
-
{text.toString().firstUpperCase()}
+
{text.toString().firstUpperCase()}
{text === false && (
diff --git a/src/routes/recurringJob/CreateRecurringJob.js b/src/routes/recurringJob/CreateRecurringJob.js
index 424a20673..a9e16e172 100644
--- a/src/routes/recurringJob/CreateRecurringJob.js
+++ b/src/routes/recurringJob/CreateRecurringJob.js
@@ -46,6 +46,7 @@ const noRetain = (val) => {
const modal = ({
item,
+ availBackupTargets,
visible,
isEdit,
onCancel,
@@ -107,7 +108,6 @@ const modal = ({
delete data.keysForlabels
}
delete data.defaultGroup
-
onOk(data)
})
}
@@ -174,6 +174,10 @@ const modal = ({
return getFieldValue('task') === 'backup' || getFieldValue('task') === 'snapshot'
}
+ const showBackupTargetDropdown = () => {
+ return getFieldValue('task') === 'backup'
+ }
+
// init params
getFieldDecorator('keys', { initialValue: isEdit && item.groups && item.groups.length > 0 ? item.groups.map((group, index) => { return { initialValue: group, index } }) : [{ index: 0, initialValue: '' }] })
getFieldDecorator('keysForlabels', { initialValue: isEdit && item.labels ? Object.keys(item.labels).map((_, index) => index) : [0] })
@@ -310,6 +314,20 @@ const modal = ({
}
+
+ {showBackupTargetDropdown()
+ &&
+ {getFieldDecorator('backupTargetName', {
+ // eslint-disable-next-line no-nested-ternary
+ initialValue: isEdit ? item.backupTarget : availBackupTargets.length > 0 ? availBackupTargets[0].name : '',
+ })(
+
+ )}
+
+ }
+
{getFieldDecorator('retain', {
initialValue: isEdit ? item.retain : 1,
@@ -373,6 +391,7 @@ const modal = ({
modal.propTypes = {
form: PropTypes.object.isRequired,
+ availBackupTargets: PropTypes.array,
visible: PropTypes.bool,
onCancel: PropTypes.func,
item: PropTypes.object,
diff --git a/src/routes/recurringJob/index.js b/src/routes/recurringJob/index.js
index 28bb3a20a..d179b18c1 100644
--- a/src/routes/recurringJob/index.js
+++ b/src/routes/recurringJob/index.js
@@ -91,7 +91,8 @@ class RecurringJob extends React.Component {
render() {
const me = this
- const { dispatch, loading, location } = this.props
+ const { dispatch, loading, location, backupTarget } = this.props
+ const availAndWritableBackupTarget = backupTarget.data.filter((item) => item.available && !item.readOnly)
const { data } = this.props.recurringJob
const { field, value } = queryString.parse(this.props.location.search)
// Front-end filtering
@@ -125,6 +126,7 @@ class RecurringJob extends React.Component {
item: this.state.selected,
visible: this.state.createRecurringJobModalVisible,
isEdit: this.state.isEdit,
+ availBackupTargets: availAndWritableBackupTarget,
onOk(newRecurringJob) {
me.setState({
...me.state,
@@ -265,9 +267,10 @@ class RecurringJob extends React.Component {
RecurringJob.propTypes = {
recurringJob: PropTypes.object,
+ backupTarget: PropTypes.object,
loading: PropTypes.bool,
location: PropTypes.object,
dispatch: PropTypes.func,
}
-export default connect(({ recurringJob, loading }) => ({ recurringJob, loading: loading.models.recurringJob }))(RecurringJob)
+export default connect(({ recurringJob, backupTarget, loading }) => ({ recurringJob, backupTarget, loading: loading.models.recurringJob }))(RecurringJob)
diff --git a/src/routes/volume/detail/CreateBackupModal.js b/src/routes/volume/detail/CreateBackupModal.js
index 34f4b27bb..fcbbf92b8 100644
--- a/src/routes/volume/detail/CreateBackupModal.js
+++ b/src/routes/volume/detail/CreateBackupModal.js
@@ -1,13 +1,31 @@
import React from 'react'
import PropTypes from 'prop-types'
-import { Form, Icon } from 'antd'
+import { Form, Select, Alert } from 'antd'
import { ModalBlur } from '../../../components'
import { BackupLabelInput } from '../../../components'
+const FormItem = Form.Item
+const Option = Select.Option
+
+const formItemLayout = {
+ labelCol: { span: 6 },
+ wrapperCol: { span: 18 },
+}
+const getLabels = (getFieldsValue) => {
+ const labels = {}
+ if (getFieldsValue().keys && getFieldsValue().key && getFieldsValue().value) {
+ getFieldsValue().keys.forEach((item) => {
+ labels[getFieldsValue().key[item]] = getFieldsValue().value[item]
+ })
+ }
+ return labels
+}
+
const modal = ({
visible,
onCancel,
onOk,
+ availBackupTargets,
form: {
getFieldDecorator,
validateFields,
@@ -18,14 +36,12 @@ const modal = ({
}) => {
function handleOk() {
validateFields((errors) => {
- if (errors) {
- return
- }
- let data = {}
- if (getFieldsValue().keys && getFieldsValue().key && getFieldsValue().value) {
- getFieldsValue().keys.forEach((item) => {
- data[getFieldsValue().key[item]] = getFieldsValue().value[item]
- })
+ if (errors) return
+
+ const labels = getLabels(getFieldsValue)
+ const data = {
+ labels,
+ backupTargetName: getFieldValue('backupTargetName'),
}
onOk(data)
})
@@ -46,15 +62,31 @@ const modal = ({
setFieldsValue,
}
+ const onChangeTask = () => {
+
+ }
+
return (
- This could take a while depending on the actual size of the volume and network bandwidth.
-
+
+
+
+ {getFieldDecorator('backupTargetName', {
+ initialValue: availBackupTargets.length > 0 ? availBackupTargets[0].name : '',
+ })(
+
+ )}
+
+
+
)
}
modal.propTypes = {
+ availBackupTargets: PropTypes.array,
form: PropTypes.object.isRequired,
visible: PropTypes.bool,
onCancel: PropTypes.func,
diff --git a/src/routes/volume/detail/Snapshots.js b/src/routes/volume/detail/Snapshots.js
index fb39d3709..bed6066ee 100644
--- a/src/routes/volume/detail/Snapshots.js
+++ b/src/routes/volume/detail/Snapshots.js
@@ -11,13 +11,14 @@ class Snapshots extends React.Component {
super(props)
this.state = {
createBackModalKey: Math.random(),
- createBackBySnapsotModalKey: Math.random(),
- createBackModalVisible: false,
- createBackBySnapsotModalVisible: false,
+ createBackBySnapshotModalKey: Math.random(),
+ createBackModalVisible: false, // click create backup button
+ createBackBySnapshotModalVisible: false, // click backup button in snapshot dropdown
currentSnapshotName: '',
snapshotBackupUrl: '',
snapshotListUrl: '',
}
+
this.onAction = (action) => {
if (action.type === 'backup') {
this.setState({
@@ -37,7 +38,7 @@ class Snapshots extends React.Component {
if (action.type === 'snapshotBackup') {
this.setState({
...this.state,
- createBackBySnapsotModalVisible: true,
+ createBackBySnapshotModalVisible: true,
currentSnapshotName: action.payload && action.payload.snapshot && action.payload.snapshot.name ? action.payload.snapshot.name : '',
snapshotBackupUrl: action.payload && action.payload.volume && action.payload.volume.actions && action.payload.volume.actions.snapshotBackup ? action.payload.volume.actions.snapshotBackup : '',
snapshotListUrl: action.payload && action.payload.volume && action.payload.volume.actions && action.payload.volume.actions.snapshotList ? action.payload.volume.actions.snapshotList : '',
@@ -139,15 +140,16 @@ class Snapshots extends React.Component {
item: {
frontend: 'iscsi',
},
+ availBackupTargets: me.props.availBackupTargets,
visible: me.state.createBackModalVisible,
- onOk(data) {
+ onOk(params) {
me.props.dispatch({
type: 'snapshotModal/backup',
payload: {
snapshotCreateUrl: me.props.volume.actions.snapshotCreate,
snapshotBackupUrl: me.props.volume.actions.snapshotBackup,
querySnapShotUrl: me.props.volume.actions.snapshotList,
- labels: data,
+ ...params,
},
})
me.setState({
@@ -166,14 +168,15 @@ class Snapshots extends React.Component {
}
}
- createBackupBySnapsotModal = () => {
+ createBackupBySnapshotModal = () => {
let me = this
return {
item: {
frontend: 'iscsi',
},
- visible: me.state.createBackBySnapsotModalVisible,
- onOk(data) {
+ availBackupTargets: me.props.availBackupTargets,
+ visible: me.state.createBackBySnapshotModalVisible,
+ onOk(params) {
if (me.state.snapshotBackupUrl && me.state.currentSnapshotName && me.state.snapshotListUrl) {
me.props.dispatch({
type: 'snapshotModal/createBackupBySnapshot',
@@ -181,13 +184,13 @@ class Snapshots extends React.Component {
snapshotBackupUrl: me.state.snapshotBackupUrl,
snapshotName: me.state.currentSnapshotName,
querySnapShotUrl: me.state.snapshotListUrl,
- labels: data,
+ ...params,
},
})
me.setState({
...me.state,
- createBackBySnapsotModalKey: Math.random(),
- createBackBySnapsotModalVisible: false,
+ createBackBySnapshotModalKey: Math.random(),
+ createBackBySnapshotModalVisible: false,
currentSnapshotName: '',
snapshotBackupUrl: '',
})
@@ -196,8 +199,8 @@ class Snapshots extends React.Component {
onCancel() {
me.setState({
...me.state,
- createBackBySnapsotModalKey: Math.random(),
- createBackBySnapsotModalVisible: false,
+ createBackBySnapshotModalKey: Math.random(),
+ createBackBySnapshotModalVisible: false,
currentSnapshotName: '',
snapshotBackupUrl: '',
})
@@ -210,6 +213,8 @@ class Snapshots extends React.Component {
return null
}
+ // console.log('🚀 ~ Snapshots ~ render ~ createBackModalVisible:', this.state.createBackModalVisible)
+ // console.log('🚀 ~ Snapshots ~ render ~ createBackBySnapshotModalVisible:', this.state.createBackBySnapshotModalVisible)
const isRestoring = () => {
if (this.props.volume.restoreStatus && this.props.volume.restoreStatus.length > 0) {
let flag = this.props.volume.restoreStatus.every((item) => {
@@ -308,7 +313,7 @@ class Snapshots extends React.Component {
Show System Hidden: { this.onAction({ type: 'toggleShowRemoved' }) }} checked={this.props.showRemoved} />