foreman_snapshot_management 1.6.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -2
- data/Rakefile +7 -2
- data/app/controllers/api/v2/snapshots_controller.rb +37 -7
- data/app/controllers/concerns/foreman/controller/parameters/snapshot.rb +1 -1
- data/app/controllers/foreman_snapshot_management/snapshots_controller.rb +5 -5
- data/app/models/concerns/fog_extensions/proxmox/snapshots/mock.rb +24 -0
- data/app/models/foreman_snapshot_management/proxmox_extensions.rb +101 -0
- data/app/models/foreman_snapshot_management/snapshot.rb +28 -28
- data/app/models/foreman_snapshot_management/vmware_extensions.rb +40 -13
- data/app/views/api/v2/snapshots/base.json.rabl +2 -0
- data/app/views/api/v2/snapshots/main.json.rabl +2 -2
- data/app/views/foreman_snapshot_management/snapshots/_index.html.erb +12 -74
- data/app/views/hosts/_snapshots_tab.html.erb +8 -0
- data/lib/foreman_snapshot_management/engine.rb +35 -16
- data/lib/foreman_snapshot_management/version.rb +1 -1
- data/lib/tasks/foreman_snapshot_management_tasks.rake +2 -2
- data/locale/de/LC_MESSAGES/foreman_snapshot_management.mo +0 -0
- data/locale/de/foreman_snapshot_management.po +195 -0
- data/locale/en/LC_MESSAGES/foreman_snapshot_management.mo +0 -0
- data/locale/en/foreman_snapshot_management.po +179 -11
- data/locale/foreman_snapshot_management.pot +259 -8
- data/locale/gemspec.rb +1 -1
- data/package.json +46 -0
- data/test/controllers/api/v2/snapshots_test.rb +250 -39
- data/test/controllers/foreman_snapshot_management/snapshots_controller_test.rb +61 -9
- data/test/factories/proxmox_factory.rb +18 -0
- data/test/test_plugin_helper.rb +3 -0
- data/webpack/components/SnapshotManagement/SnapshotManagement.js +84 -0
- data/webpack/components/SnapshotManagement/SnapshotManagementActions.js +212 -0
- data/webpack/components/SnapshotManagement/SnapshotManagementConstants.js +9 -0
- data/webpack/components/SnapshotManagement/SnapshotManagementReducer.js +100 -0
- data/webpack/components/SnapshotManagement/SnapshotManagementSelectors.js +8 -0
- data/webpack/components/SnapshotManagement/__tests__/SnapshotManagementActions.test.js +123 -0
- data/webpack/components/SnapshotManagement/__tests__/SnapshotManagementReducer.test.js +157 -0
- data/webpack/components/SnapshotManagement/__tests__/__snapshots__/SnapshotManagementActions.test.js.snap +314 -0
- data/webpack/components/SnapshotManagement/__tests__/__snapshots__/SnapshotManagementReducer.test.js.snap +214 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/SnapshotForm.js +118 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/SnapshotFormConstants.js +5 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/__tests__/SnapshotForm.test.js +26 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/__tests__/__snapshots__/SnapshotForm.test.js.snap +476 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/index.js +19 -0
- data/webpack/components/SnapshotManagement/components/SnapshotForm/snapshotForm.scss +3 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/SnapshotFormModal.js +37 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/SnapshotFormModalConstants.js +1 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/__tests__/SnapshotFormModal.test.js +19 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/__tests__/__snapshots__/SnapshotFormModal.test.js.snap +19 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/index.js +12 -0
- data/webpack/components/SnapshotManagement/components/SnapshotFormModal/useSnapshotFormModal.js +7 -0
- data/webpack/components/SnapshotManagement/components/SnapshotList/SnapshotList.js +314 -0
- data/webpack/components/SnapshotManagement/components/SnapshotList/SnapshotListHelper.js +70 -0
- data/webpack/components/SnapshotManagement/components/SnapshotList/__tests__/SnapshotList.test.js +88 -0
- data/webpack/components/SnapshotManagement/components/SnapshotList/__tests__/__snapshots__/SnapshotList.test.js.snap +1081 -0
- data/webpack/components/SnapshotManagement/components/SnapshotList/snapshotList.scss +13 -0
- data/webpack/components/SnapshotManagement/index.js +33 -0
- data/webpack/components/SnapshotManagement/snapshotManagement.scss +5 -0
- data/webpack/global_index.js +7 -0
- data/webpack/global_test_setup.js +11 -0
- data/webpack/index.js +8 -0
- data/webpack/reducers.js +7 -0
- data/webpack/test_setup.js +17 -0
- metadata +50 -37
@@ -0,0 +1,19 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useDispatch } from 'react-redux';
|
3
|
+
|
4
|
+
import { submitForm } from 'foremanReact/redux/actions/common/forms';
|
5
|
+
|
6
|
+
import SnapshotForm from './SnapshotForm';
|
7
|
+
|
8
|
+
const WrappedSnapshotForm = props => {
|
9
|
+
const dispatch = useDispatch();
|
10
|
+
|
11
|
+
return (
|
12
|
+
<SnapshotForm
|
13
|
+
submitForm={(...args) => dispatch(submitForm(...args))}
|
14
|
+
{...props}
|
15
|
+
/>
|
16
|
+
);
|
17
|
+
};
|
18
|
+
|
19
|
+
export default WrappedSnapshotForm;
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
|
4
|
+
import ForemanModal from 'foremanReact/components/ForemanModal';
|
5
|
+
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
|
7
|
+
import SnapshotForm from '../SnapshotForm';
|
8
|
+
|
9
|
+
import { SNAPSHOT_FORM_MODAL } from './SnapshotFormModalConstants';
|
10
|
+
|
11
|
+
const SnapshotFormModal = ({ host, setModalClosed, ...props }) => (
|
12
|
+
<ForemanModal
|
13
|
+
id={SNAPSHOT_FORM_MODAL}
|
14
|
+
title={sprintf(__('Create Snapshot for %s'), host.name)}
|
15
|
+
enforceFocus
|
16
|
+
>
|
17
|
+
<ForemanModal.Header closeButton={false} />
|
18
|
+
|
19
|
+
<div>
|
20
|
+
<SnapshotForm
|
21
|
+
setModalClosed={setModalClosed}
|
22
|
+
hostId={host.id}
|
23
|
+
{...props}
|
24
|
+
/>
|
25
|
+
</div>
|
26
|
+
</ForemanModal>
|
27
|
+
);
|
28
|
+
|
29
|
+
SnapshotFormModal.propTypes = {
|
30
|
+
host: PropTypes.shape({
|
31
|
+
id: PropTypes.number.isRequired,
|
32
|
+
name: PropTypes.string.isRequired,
|
33
|
+
}).isRequired,
|
34
|
+
setModalClosed: PropTypes.func.isRequired,
|
35
|
+
};
|
36
|
+
|
37
|
+
export default SnapshotFormModal;
|
@@ -0,0 +1 @@
|
|
1
|
+
export const SNAPSHOT_FORM_MODAL = 'foremanSnapshotMgmtSnapshotFormModal';
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import {
|
2
|
+
testComponentSnapshotsWithFixtures,
|
3
|
+
// shallowRenderComponentWithFixtures,
|
4
|
+
} from 'react-redux-test-utils';
|
5
|
+
// import configureStore from 'redux-mock-store';
|
6
|
+
|
7
|
+
import SnapshotFormModal from '../SnapshotFormModal';
|
8
|
+
|
9
|
+
// const mockStore = configureStore([]);
|
10
|
+
|
11
|
+
const setModalClosed = () => null;
|
12
|
+
const fixtures = {
|
13
|
+
normal: { host: { id: 42, name: 'deep.thought' }, setModalClosed },
|
14
|
+
};
|
15
|
+
|
16
|
+
describe('SnapshotFormModal', () => {
|
17
|
+
describe('renders', () =>
|
18
|
+
testComponentSnapshotsWithFixtures(SnapshotFormModal, fixtures));
|
19
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`SnapshotFormModal renders normal 1`] = `
|
4
|
+
<ConnectedForemanModal
|
5
|
+
enforceFocus={true}
|
6
|
+
id="foremanSnapshotMgmtSnapshotFormModal"
|
7
|
+
title="Create Snapshot for deep.thought"
|
8
|
+
>
|
9
|
+
<ForemanModalHeader
|
10
|
+
closeButton={false}
|
11
|
+
/>
|
12
|
+
<div>
|
13
|
+
<WrappedSnapshotForm
|
14
|
+
hostId={42}
|
15
|
+
setModalClosed={[Function]}
|
16
|
+
/>
|
17
|
+
</div>
|
18
|
+
</ConnectedForemanModal>
|
19
|
+
`;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
import useSnapshotFormModal from './useSnapshotFormModal';
|
4
|
+
import SnapshotFormModal from './SnapshotFormModal';
|
5
|
+
|
6
|
+
const WrappedSnapshotFormModal = props => {
|
7
|
+
const { setModalClosed } = useSnapshotFormModal();
|
8
|
+
|
9
|
+
return <SnapshotFormModal setModalClosed={setModalClosed} {...props} />;
|
10
|
+
};
|
11
|
+
|
12
|
+
export default WrappedSnapshotFormModal;
|
data/webpack/components/SnapshotManagement/components/SnapshotFormModal/useSnapshotFormModal.js
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
|
2
|
+
|
3
|
+
import { SNAPSHOT_FORM_MODAL } from './SnapshotFormModalConstants';
|
4
|
+
|
5
|
+
const useSnapshotFormModal = () => useForemanModal({ id: SNAPSHOT_FORM_MODAL });
|
6
|
+
|
7
|
+
export default useSnapshotFormModal;
|
@@ -0,0 +1,314 @@
|
|
1
|
+
import React, { Component } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import {
|
4
|
+
Alert,
|
5
|
+
// Button,
|
6
|
+
Table as PfTable,
|
7
|
+
FormControl,
|
8
|
+
inlineEditFormatterFactory,
|
9
|
+
} from 'patternfly-react';
|
10
|
+
import { cloneDeep, findIndex } from 'lodash';
|
11
|
+
|
12
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
13
|
+
import {
|
14
|
+
Table,
|
15
|
+
TableBody,
|
16
|
+
column,
|
17
|
+
headerFormatterWithProps,
|
18
|
+
cellFormatterWithProps,
|
19
|
+
} from 'foremanReact/components/common/table';
|
20
|
+
import ShortDateTime from 'foremanReact/components/common/dates/ShortDateTime';
|
21
|
+
import AlertBody from 'foremanReact/components/common/Alert/AlertBody';
|
22
|
+
import Loading from 'foremanReact/components/Loading/Loading';
|
23
|
+
import 'foremanReact/redux/API';
|
24
|
+
|
25
|
+
import { renderListEntryButtons } from './SnapshotListHelper';
|
26
|
+
import './snapshotList.scss';
|
27
|
+
|
28
|
+
class SnapshotList extends Component {
|
29
|
+
constructor(props) {
|
30
|
+
super(props);
|
31
|
+
this.state = {
|
32
|
+
columns: this.defineColumns(),
|
33
|
+
editMode: false,
|
34
|
+
rows: cloneDeep(props.snapshots),
|
35
|
+
};
|
36
|
+
}
|
37
|
+
|
38
|
+
defineColumns() {
|
39
|
+
const {
|
40
|
+
canDelete,
|
41
|
+
canRevert,
|
42
|
+
canUpdate,
|
43
|
+
host,
|
44
|
+
deleteAction,
|
45
|
+
updateAction,
|
46
|
+
rollbackAction,
|
47
|
+
} = this.props;
|
48
|
+
|
49
|
+
const inlineEditController = {
|
50
|
+
isEditing: ({ rowData }) => rowData.backup !== undefined,
|
51
|
+
onActivate: ({ rowData }) => {
|
52
|
+
const rows = cloneDeep(this.state.rows);
|
53
|
+
const index = findIndex(rows, { id: rowData.id });
|
54
|
+
|
55
|
+
rows[index].backup = cloneDeep(rows[index]);
|
56
|
+
|
57
|
+
this.setState({ rows, editMode: true });
|
58
|
+
},
|
59
|
+
onConfirm: ({ rowData }) => {
|
60
|
+
const rows = cloneDeep(this.state.rows);
|
61
|
+
const index = findIndex(rows, { id: rowData.id });
|
62
|
+
|
63
|
+
delete rows[index].backup;
|
64
|
+
|
65
|
+
this.setState({ rows, editMode: false });
|
66
|
+
updateAction(host, rowData);
|
67
|
+
},
|
68
|
+
onCancel: ({ rowData }) => {
|
69
|
+
const rows = cloneDeep(this.state.rows);
|
70
|
+
const index = findIndex(rows, { id: rowData.id });
|
71
|
+
|
72
|
+
rows[index] = cloneDeep(rows[index].backup);
|
73
|
+
delete rows[index].backup;
|
74
|
+
|
75
|
+
this.setState({ rows, editMode: false });
|
76
|
+
},
|
77
|
+
onChange: (value, { rowData, property }) => {
|
78
|
+
const rows = cloneDeep(this.state.rows);
|
79
|
+
const index = findIndex(rows, { id: rowData.id });
|
80
|
+
|
81
|
+
rows[index][property] = value;
|
82
|
+
|
83
|
+
this.setState({ rows });
|
84
|
+
},
|
85
|
+
};
|
86
|
+
this.inlineEditController = inlineEditController;
|
87
|
+
|
88
|
+
const renderButtons = renderListEntryButtons(
|
89
|
+
canDelete,
|
90
|
+
canRevert,
|
91
|
+
canUpdate,
|
92
|
+
host,
|
93
|
+
rollbackAction,
|
94
|
+
deleteAction,
|
95
|
+
inlineEditController
|
96
|
+
);
|
97
|
+
const inlineEditButtonCellFormatter = inlineEditFormatterFactory({
|
98
|
+
isEditing: additionalData => this.state.editMode,
|
99
|
+
renderValue: renderButtons(false),
|
100
|
+
renderEdit: renderButtons(true),
|
101
|
+
});
|
102
|
+
|
103
|
+
const inlineEditFormatter = inlineEditFormatterFactory({
|
104
|
+
isEditing: additionalData => {
|
105
|
+
if (
|
106
|
+
additionalData.property === 'name' &&
|
107
|
+
!this.props.capabilities.editableSnapshotName
|
108
|
+
)
|
109
|
+
return false;
|
110
|
+
return inlineEditController.isEditing(additionalData);
|
111
|
+
},
|
112
|
+
renderValue: (value, additionalData) => {
|
113
|
+
let date = '';
|
114
|
+
if (
|
115
|
+
additionalData.property === 'name' &&
|
116
|
+
additionalData.rowData.formatted_created_at
|
117
|
+
)
|
118
|
+
date = (
|
119
|
+
<span className="snapshot-date">
|
120
|
+
<ShortDateTime
|
121
|
+
date={new Date(additionalData.rowData.formatted_created_at)}
|
122
|
+
defaultValue={__('N/A')}
|
123
|
+
showRelativeTimeTooltip
|
124
|
+
/>
|
125
|
+
</span>
|
126
|
+
);
|
127
|
+
return (
|
128
|
+
<span className="static description">
|
129
|
+
{value}
|
130
|
+
<br />
|
131
|
+
{date}
|
132
|
+
</span>
|
133
|
+
);
|
134
|
+
},
|
135
|
+
renderEdit: (value, additionalData) => {
|
136
|
+
let type = 'input';
|
137
|
+
if (additionalData.property === 'description') type = 'textarea';
|
138
|
+
return (
|
139
|
+
<FormControl
|
140
|
+
type="text"
|
141
|
+
defaultValue={value}
|
142
|
+
onBlur={e =>
|
143
|
+
inlineEditController.onChange(e.target.value, additionalData)
|
144
|
+
}
|
145
|
+
componentClass={type}
|
146
|
+
/>
|
147
|
+
);
|
148
|
+
},
|
149
|
+
});
|
150
|
+
const editCellFormatters = [cellFormatterWithProps];
|
151
|
+
if (canUpdate) editCellFormatters.unshift(inlineEditFormatter);
|
152
|
+
|
153
|
+
const columns = [
|
154
|
+
column(
|
155
|
+
'name',
|
156
|
+
__('Snapshot'),
|
157
|
+
[headerFormatterWithProps],
|
158
|
+
editCellFormatters
|
159
|
+
),
|
160
|
+
column(
|
161
|
+
'description',
|
162
|
+
__('Description'),
|
163
|
+
[headerFormatterWithProps],
|
164
|
+
editCellFormatters
|
165
|
+
),
|
166
|
+
];
|
167
|
+
if (canDelete || canUpdate || canRevert)
|
168
|
+
columns.push(
|
169
|
+
column(
|
170
|
+
'',
|
171
|
+
__('Action'),
|
172
|
+
[headerFormatterWithProps],
|
173
|
+
[inlineEditButtonCellFormatter],
|
174
|
+
{ className: 'action-buttons' }
|
175
|
+
)
|
176
|
+
);
|
177
|
+
return columns;
|
178
|
+
}
|
179
|
+
|
180
|
+
componentDidMount() {
|
181
|
+
this.props.loadSnapshots(this.props.host.id);
|
182
|
+
}
|
183
|
+
|
184
|
+
// FIXME: Remove soon, as this is deprecated!
|
185
|
+
componentWillReceiveProps(newProps) {
|
186
|
+
if (newProps.snapshots !== this.props.snapshots) {
|
187
|
+
this.setState({ rows: newProps.snapshots });
|
188
|
+
}
|
189
|
+
if (newProps.needsReload) {
|
190
|
+
newProps.loadSnapshots(newProps.host.id);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
getBodyMessage() {
|
195
|
+
if (this.props.isLoading || this.props.isWorking)
|
196
|
+
return <Loading textSize="sm" />;
|
197
|
+
|
198
|
+
if (this.props.hasError)
|
199
|
+
return (
|
200
|
+
<Alert
|
201
|
+
variant="danger"
|
202
|
+
isInline
|
203
|
+
title={__('Failed to load snapshot list')}
|
204
|
+
>
|
205
|
+
<AlertBody title={__('Failed to load snapshot list')}>
|
206
|
+
{/* IMHO the line-break should be done by AlertBody :-( */}
|
207
|
+
<br />
|
208
|
+
{this.props.error.message}
|
209
|
+
</AlertBody>
|
210
|
+
</Alert>
|
211
|
+
);
|
212
|
+
|
213
|
+
return undefined;
|
214
|
+
}
|
215
|
+
|
216
|
+
render() {
|
217
|
+
const { columns } = this.state;
|
218
|
+
const bodyMessage = this.getBodyMessage();
|
219
|
+
|
220
|
+
return (
|
221
|
+
<div>
|
222
|
+
{/*
|
223
|
+
<Button
|
224
|
+
disabled={this.props.isLoading}
|
225
|
+
onClick={() => this.props.loadSnapshots(this.props.host.id)}
|
226
|
+
>
|
227
|
+
ReloadData
|
228
|
+
</Button>
|
229
|
+
*/}
|
230
|
+
<Table
|
231
|
+
caption="Snapshot List"
|
232
|
+
columns={columns}
|
233
|
+
rows={this.state.rows}
|
234
|
+
bodyMessage={bodyMessage}
|
235
|
+
inlineEdit
|
236
|
+
components={{
|
237
|
+
body: {
|
238
|
+
row: PfTable.InlineEditRow,
|
239
|
+
cell: cellProps => cellProps.children,
|
240
|
+
},
|
241
|
+
}}
|
242
|
+
>
|
243
|
+
<PfTable.Header key="header" />
|
244
|
+
<TableBody
|
245
|
+
key="body"
|
246
|
+
columns={columns}
|
247
|
+
rows={this.state.rows}
|
248
|
+
message={bodyMessage}
|
249
|
+
rowKey="id"
|
250
|
+
onRow={(rowData, { rowIndex }) => ({
|
251
|
+
role: 'row',
|
252
|
+
isEditing: () => this.inlineEditController.isEditing({ rowData }),
|
253
|
+
onCancel: () =>
|
254
|
+
this.inlineEditController.onCancel({ rowData, rowIndex }),
|
255
|
+
onConfirm: () =>
|
256
|
+
this.inlineEditController.onConfirm({ rowData, rowIndex }),
|
257
|
+
last: rowIndex === this.state.rows.length - 1,
|
258
|
+
})}
|
259
|
+
/>
|
260
|
+
</Table>
|
261
|
+
</div>
|
262
|
+
);
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
SnapshotList.propTypes = {
|
267
|
+
/*
|
268
|
+
children: PropTypes.node,
|
269
|
+
className: PropTypes.string,
|
270
|
+
*/
|
271
|
+
host: PropTypes.shape({
|
272
|
+
id: PropTypes.number.isRequired,
|
273
|
+
name: PropTypes.string.isRequired,
|
274
|
+
}).isRequired,
|
275
|
+
loadSnapshots: PropTypes.func.isRequired,
|
276
|
+
deleteAction: PropTypes.func.isRequired,
|
277
|
+
updateAction: PropTypes.func.isRequired,
|
278
|
+
rollbackAction: PropTypes.func.isRequired,
|
279
|
+
isLoading: PropTypes.bool,
|
280
|
+
isWorking: PropTypes.bool,
|
281
|
+
hasError: PropTypes.bool,
|
282
|
+
error: PropTypes.shape({ message: PropTypes.string }),
|
283
|
+
snapshots: PropTypes.array,
|
284
|
+
|
285
|
+
// permissions:
|
286
|
+
canDelete: PropTypes.bool,
|
287
|
+
canRevert: PropTypes.bool,
|
288
|
+
canUpdate: PropTypes.bool,
|
289
|
+
|
290
|
+
// capabilities
|
291
|
+
capabilities: PropTypes.shape({
|
292
|
+
editableSnapshotName: PropTypes.bool,
|
293
|
+
}),
|
294
|
+
};
|
295
|
+
|
296
|
+
SnapshotList.defaultProps = {
|
297
|
+
/*
|
298
|
+
className: '',
|
299
|
+
children: null,
|
300
|
+
*/
|
301
|
+
isLoading: true,
|
302
|
+
isWorking: false,
|
303
|
+
hasError: false,
|
304
|
+
error: undefined,
|
305
|
+
snapshots: [],
|
306
|
+
canDelete: false,
|
307
|
+
canRevert: false,
|
308
|
+
canUpdate: false,
|
309
|
+
capabilities: {
|
310
|
+
editableSnapshotName: true,
|
311
|
+
},
|
312
|
+
};
|
313
|
+
|
314
|
+
export default SnapshotList;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Button, Icon } from 'patternfly-react';
|
3
|
+
|
4
|
+
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
5
|
+
|
6
|
+
import './snapshotList.scss';
|
7
|
+
|
8
|
+
export const renderListEntryButtons = (
|
9
|
+
canDelete,
|
10
|
+
canRevert,
|
11
|
+
canUpdate,
|
12
|
+
host,
|
13
|
+
snapshotRollbackAction,
|
14
|
+
snapshotDeleteAction,
|
15
|
+
inlineEditController
|
16
|
+
) => disabled => (value, additionalData) => {
|
17
|
+
const buttons = [];
|
18
|
+
|
19
|
+
// Edit Button
|
20
|
+
if (canUpdate) {
|
21
|
+
buttons.push(
|
22
|
+
<Button
|
23
|
+
key="edit-button"
|
24
|
+
bsStyle="default"
|
25
|
+
disabled={disabled}
|
26
|
+
onClick={() => inlineEditController.onActivate(additionalData)}
|
27
|
+
>
|
28
|
+
<Icon type="pf" name="edit" title={__('edit entry')} />
|
29
|
+
</Button>
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
33
|
+
// Rollback button
|
34
|
+
if (canRevert) {
|
35
|
+
buttons.push(
|
36
|
+
<Button
|
37
|
+
key="rollback-button"
|
38
|
+
bsStyle="default"
|
39
|
+
disabled={disabled}
|
40
|
+
onClick={() =>
|
41
|
+
window.confirm(
|
42
|
+
sprintf(__('Rollback to "%s"?'), additionalData.rowData.name)
|
43
|
+
) && snapshotRollbackAction(host, additionalData.rowData)
|
44
|
+
}
|
45
|
+
>
|
46
|
+
<Icon type="pf" name="history" title={__('Rollback')} />
|
47
|
+
</Button>
|
48
|
+
);
|
49
|
+
}
|
50
|
+
|
51
|
+
// Delete Button
|
52
|
+
if (canDelete) {
|
53
|
+
buttons.push(
|
54
|
+
<Button
|
55
|
+
key="delete-button"
|
56
|
+
bsStyle="default"
|
57
|
+
disabled={disabled}
|
58
|
+
onClick={() =>
|
59
|
+
window.confirm(
|
60
|
+
sprintf(__('Delete Snapshot "%s"?'), additionalData.rowData.name)
|
61
|
+
) && snapshotDeleteAction(host, additionalData.rowData)
|
62
|
+
}
|
63
|
+
>
|
64
|
+
<Icon type="pf" name="delete" title={__('Delete')} />
|
65
|
+
</Button>
|
66
|
+
);
|
67
|
+
}
|
68
|
+
|
69
|
+
return <td className="action-buttons">{buttons}</td>;
|
70
|
+
};
|