Skip to content

Commit

Permalink
Allow to choose backup target when create volume backup and recurring…
Browse files Browse the repository at this point in the history
… job

Signed-off-by: andy.lee <andy.lee@suse.com>
  • Loading branch information
a110605 committed Jun 18, 2024
1 parent 41cac68 commit da9a084
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 133 deletions.
92 changes: 45 additions & 47 deletions src/components/BackupLabelInput/BackupLabelInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,64 +37,62 @@ class BackupLabelInput extends React.Component {

render() {
const { getFieldDecorator, getFieldValue } = this.props.form
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 16, offset: 4 },
},
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
}
getFieldDecorator('keys', { initialValue: [] })
const keys = getFieldValue('keys')
const formItems = keys.map((k, index) => (
<div style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'start', height: '60px' }} key={index}>
<Form.Item
required={false}
key={`key${k}`}
style={{ marginBottom: 0 }}
>
{getFieldDecorator(`key[${k}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [
{
required: true,
whitespace: true,
message: 'key is required',
},
],
})(<Input placeholder="Labels Key" style={{ marginRight: 8 }} />)}
</Form.Item>
<Form.Item
required={false}
key={`value${k}`}
style={{ marginBottom: 0 }}
>
{getFieldDecorator(`value[${k}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [
{
required: true,
whitespace: true,
message: 'value is required',
},
],
})(<Input placeholder="Labels Value" style={{ marginRight: 8 }} />)}
</Form.Item>{keys.length > 0 ? (
<Icon
style={{ marginTop: '12px' }}
className="dynamic-delete-button"
type="minus-circle-o"
onClick={() => this.remove(k)}
/>) : null}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', height: 60, marginLeft: 60 }} key={index}>
<Form.Item
required={false}
key={`key${k}`}
style={{ marginBottom: 0 }}
>
{getFieldDecorator(`key[${k}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [
{
required: true,
whitespace: true,
message: 'key is required',
},
],
})(<Input placeholder="Labels Key" style={{ marginRight: 8 }} />)}
</Form.Item>
<Form.Item
required={false}
key={`value${k}`}
style={{ marginBottom: 0 }}
>
{getFieldDecorator(`value[${k}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [
{
required: true,
whitespace: true,
message: 'value is required',
},
],
})(<Input placeholder="Labels Value" style={{ marginRight: 8 }} />)}
</Form.Item>{keys.length > 0 ? (
<Icon
style={{ marginTop: '12px' }}
className="dynamic-delete-button"
type="minus-circle-o"
onClick={() => this.remove(k)}
/>) : null}
</div>
))
return (
<Form onSubmit={this.handleSubmit}>
{formItems}
<Form.Item {...formItemLayoutWithOutLabel}>
<Form.Item label="Labels" style={{ display: 'flex' }} {...formItemLayout}>
<Button type="dashed" onClick={this.add} style={{ width: '100%' }}>
<Icon type="plus" /> Add Labels for Backup
<Icon type="plus" /> Add Labels
</Button>
</Form.Item>
{formItems}
</Form>
)
}
Expand Down
46 changes: 0 additions & 46 deletions src/models/backupTarget.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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: {
Expand All @@ -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)
}
Expand All @@ -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}.`)
}
Expand All @@ -69,7 +57,6 @@ export default {
*edit({
payload,
}, { call, put }) {
// console.log('🚀 ~edit payload:', payload)
yield call(updateBackupTarget, payload)
yield put({ type: 'query' })
},
Expand All @@ -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 {
Expand Down Expand Up @@ -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 }
},
Expand Down
8 changes: 4 additions & 4 deletions src/models/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand All @@ -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 })
Expand Down
4 changes: 2 additions & 2 deletions src/routes/backupTarget/BackupTargetList.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function list({ loading, dataSource, deleteBackupTarget, editBackupTarget, rowSe
sorter: (a, b) => a.default - b.default,
render: (text) => {
return (
<div style={{ color: `${text === true ? '#27ae60' : 'auto'}` }}>{text.toString().firstUpperCase()}</div>
<div>{text.toString().firstUpperCase()}</div>
)
},
}, {
Expand All @@ -81,7 +81,7 @@ function list({ loading, dataSource, deleteBackupTarget, editBackupTarget, rowSe
render: (text) => {
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div style={{ color: `${text === false ? 'red' : 'auto'}` }}>{text.toString().firstUpperCase()}</div>
<div>{text.toString().firstUpperCase()}</div>
{text === false && (
<Tooltip title="This backup target is unavailable, please check the URL and credential secret are all correct.">
<Icon type="exclamation-circle" style={{ color: 'red', marginLeft: 4, alignSelf: 'center' }} />
Expand Down
21 changes: 20 additions & 1 deletion src/routes/recurringJob/CreateRecurringJob.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const noRetain = (val) => {

const modal = ({
item,
availBackupTargets,
visible,
isEdit,
onCancel,
Expand Down Expand Up @@ -107,7 +108,6 @@ const modal = ({
delete data.keysForlabels
}
delete data.defaultGroup

onOk(data)
})
}
Expand Down Expand Up @@ -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] })
Expand Down Expand Up @@ -310,6 +314,20 @@ const modal = ({
</FormItem>
</Tooltip>}
</div>
<div>
{showBackupTargetDropdown()
&& <FormItem label="Backup Target" {...formItemLayout}>
{getFieldDecorator('backupTargetName', {
// eslint-disable-next-line no-nested-ternary
initialValue: isEdit ? item.backupTarget : availBackupTargets.length > 0 ? availBackupTargets[0].name : '',
})(
<Select disabled={isEdit} style={{ width: '80%' }}>
{availBackupTargets.map(bkTarget => <Option key={bkTarget.name} value={bkTarget.name}>{bkTarget.name}</Option>)}
</Select>
)}
</FormItem>
}
</div>
<FormItem label="Retain" hasFeedback {...formItemLayout}>
{getFieldDecorator('retain', {
initialValue: isEdit ? item.retain : 1,
Expand Down Expand Up @@ -373,6 +391,7 @@ const modal = ({

modal.propTypes = {
form: PropTypes.object.isRequired,
availBackupTargets: PropTypes.array,
visible: PropTypes.bool,
onCancel: PropTypes.func,
item: PropTypes.object,
Expand Down
7 changes: 5 additions & 2 deletions src/routes/recurringJob/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Loading

0 comments on commit da9a084

Please sign in to comment.