TasksList.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. import React, { Component } from 'react'
  2. import Button from 'material-ui/Button'
  3. import Base from '../common/Base'
  4. import Paper from 'material-ui/Paper'
  5. import Table, { TableHead, TableBody, TableRow, TableCell } from 'material-ui/Table'
  6. import Dialog, { DialogActions, DialogContent, DialogContentText, DialogTitle } from 'material-ui/Dialog'
  7. import TextField from 'material-ui/TextField'
  8. import { InputLabel } from 'material-ui/Input'
  9. import { FormControl } from 'material-ui/Form'
  10. import Select from 'material-ui/Select'
  11. import MenuItem from 'material-ui/Menu/MenuItem'
  12. import Typography from 'material-ui/Typography'
  13. import List, { ListItem, ListItemText, ListItemSecondaryAction } from 'material-ui/List'
  14. import IconButton from 'material-ui/IconButton'
  15. import AddIcon from '../icons/AddIcon'
  16. import RemoveIcon from '../icons/RemoveIcon'
  17. import { isEqual, isEmpty, filter, union, difference, defer } from 'lodash'
  18. import { ODOO, DOCKER, REQUEST, GIT } from '../../constants/ResourceNames'
  19. import { post, get } from '../../actions'
  20. import { connect } from 'react-redux'
  21. import { withStyles } from 'material-ui/styles'
  22. const styles = theme => ({
  23. gap: {
  24. marginTop: 25
  25. },
  26. transfer: {
  27. display: 'flex',
  28. marginTop: theme.spacing.unit * 3
  29. },
  30. transferPanels: {
  31. height: '100%',
  32. padding: 15,
  33. flexGrow: 1
  34. },
  35. transferModules: {
  36. height: 300,
  37. overflowY: 'auto'
  38. }
  39. })
  40. class TasksList extends Component {
  41. constructor(props) {
  42. super(props)
  43. this.state = {
  44. showDialog: null,
  45. isDialogValid: true,
  46. name: '',
  47. nameConfirmation: '',
  48. odoos: [],
  49. modules: [],
  50. selectedOdoo: '',
  51. modulesToInstall: []
  52. }
  53. }
  54. /**
  55. *
  56. */
  57. componentDidMount() {
  58. this.props.loadData()
  59. }
  60. /**
  61. *
  62. */
  63. handleShowDialog = (taskName, e) => {
  64. if (taskName === 'create-odoo') {
  65. this.showDialog(taskName)
  66. }
  67. if (taskName === 'show-modules') {
  68. Promise.all([
  69. this.props.loadContainers(),
  70. this.props.loadRepositories()
  71. ]).then(data => {
  72. this.setState({
  73. odoos: data[0].payload.containers,
  74. modules: data[1].payload.repositories
  75. }, () => this.showDialog(taskName))
  76. })
  77. }
  78. }
  79. /**
  80. *
  81. */
  82. showDialog = dialog => {
  83. this.setState({
  84. showDialog: dialog
  85. })
  86. }
  87. /**
  88. *
  89. */
  90. handleCloseDialog = taskName => {
  91. defer(() => {
  92. this.setState({
  93. showDialog: null
  94. })
  95. })
  96. }
  97. /**
  98. *
  99. */
  100. handleChangeName = e => {
  101. if (isEqual(e.target.id, 'name')) {
  102. this.setState({
  103. name: e.target.value
  104. }, this.handleStateChange)
  105. }
  106. if (isEqual(e.target.id, 'nameConfirmation')) {
  107. this.setState({
  108. nameConfirmation: e.target.value
  109. }, this.handleStateChange)
  110. }
  111. }
  112. /**
  113. *
  114. */
  115. handleStateChange = () => {
  116. if (isEqual(this.state.name, this.state.nameConfirmation)) {
  117. this.setState({
  118. isDialogValid: true
  119. })
  120. } else {
  121. this.setState({
  122. isDialogValid: false
  123. })
  124. }
  125. }
  126. /**
  127. *
  128. */
  129. handleChangeOdooSystem = e => {
  130. defer(() => {
  131. this.setState({
  132. [e.target.name]: e.target.value
  133. })
  134. })
  135. }
  136. /**
  137. *
  138. */
  139. handleModulesSearch = e => {
  140. let value = e.target.value
  141. defer(() => {
  142. if (isEmpty(value)) {
  143. this.setState({
  144. modules: this.props.repositories
  145. })
  146. return
  147. }
  148. let filteredModules = filter(this.props.repositories, item => {
  149. return item.indexOf(value.toLowerCase()) !== -1
  150. })
  151. this.setState({
  152. modules: filteredModules
  153. })
  154. })
  155. }
  156. /**
  157. *
  158. */
  159. handleAcceptDialog = e => {
  160. // handling odoo creating
  161. if (this.state.showDialog === 'create-odoo') {
  162. const { name, nameConfirmation } = this.state
  163. if (isEmpty(name) || isEmpty(nameConfirmation)) {
  164. return
  165. }
  166. if (isEqual(name, nameConfirmation)) {
  167. this.props.createOdoo(name)
  168. this.setState({
  169. showDialog: null,
  170. name: '',
  171. nameConfirmation: ''
  172. })
  173. }
  174. }
  175. // handling copying modules
  176. if (this.state.showDialog === 'show-modules') {
  177. const { selectedOdoo, modulesToInstall } = this.state
  178. if (isEmpty(selectedOdoo) || isEmpty(modulesToInstall)) {
  179. return
  180. }
  181. this.setState({
  182. showDialog: null,
  183. selectedOdoo: '',
  184. modulesToInstall: []
  185. }, () => this.props.installModules(selectedOdoo, modulesToInstall))
  186. }
  187. }
  188. /**
  189. *
  190. */
  191. handleAddModule = (index, e) => {
  192. defer(() => {
  193. const item = this.state.modules[index]
  194. this.setState({
  195. modules: difference(this.state.modules, [item]),
  196. modulesToInstall: union(this.state.modulesToInstall, [item])
  197. })
  198. })
  199. }
  200. /**
  201. *
  202. */
  203. handleRemoveModule = (index, e) => {
  204. defer(() => {
  205. const item = this.state.modulesToInstall[index]
  206. this.setState({
  207. modules: union(this.state.modules, [item]),
  208. modulesToInstall: difference(this.state.modulesToInstall, [item])
  209. })
  210. })
  211. }
  212. /**
  213. *
  214. */
  215. render() {
  216. const { classes } = this.props
  217. const { isDialogValid, showDialog } = this.state
  218. return (
  219. <Base title={this.props.title}>
  220. <Paper>
  221. <Table>
  222. <TableHead>
  223. <TableRow>
  224. <TableCell>Nombre</TableCell>
  225. <TableCell>Última ejecución</TableCell>
  226. <TableCell>Usuario</TableCell>
  227. <TableCell />
  228. </TableRow>
  229. </TableHead>
  230. <TableBody>
  231. <TableRow>
  232. <TableCell>Crear contenedor Odoo</TableCell>
  233. <TableCell>Nunca</TableCell>
  234. <TableCell>Anónimo</TableCell>
  235. <TableCell>
  236. <Button variant='raised' color='primary' data-action='create' onClick={e => this.handleShowDialog('create-odoo', e)}>Ejecutar</Button>
  237. </TableCell>
  238. </TableRow>
  239. <TableRow>
  240. <TableCell>Copiar/actualizar módulos de Odoo</TableCell>
  241. <TableCell>Nunca</TableCell>
  242. <TableCell>Anónimo</TableCell>
  243. <TableCell>
  244. <Button variant='raised' color='primary' data-action='create' onClick={e => this.handleShowDialog('show-modules', e)}>Ejecutar</Button>
  245. </TableCell>
  246. </TableRow>
  247. </TableBody>
  248. </Table>
  249. </Paper>
  250. {/* Dialog for create odoo container */}
  251. <Dialog open={showDialog === 'create-odoo'} onClose={this.handleCloseDialog}>
  252. <DialogTitle>Confirmar</DialogTitle>
  253. <DialogContent>
  254. <DialogContentText>Estás solicitando crear un nuevo contenedor Odoo. Tenga en cuenta que ésta tarea puede tardar unos instantes dependiendo del tráfico de red y del uso de los recursos del servidor</DialogContentText>
  255. <TextField
  256. id='name'
  257. margin='dense'
  258. label='Nombre del sistema'
  259. type='text'
  260. autoComplete='off'
  261. onKeyUp={this.handleChangeName}
  262. autoFocus
  263. fullWidth
  264. />
  265. <TextField
  266. id='nameConfirmation'
  267. margin='dense'
  268. label='Repita el nombre del sistema'
  269. type='text'
  270. autoComplete='off'
  271. error={!isDialogValid}
  272. onKeyUp={this.handleChangeName}
  273. fullWidth
  274. />
  275. </DialogContent>
  276. <DialogActions>
  277. <Button color='primary' onClick={this.handleCloseDialog}>Cancelar</Button>
  278. <Button color='primary' onClick={this.handleAcceptDialog}>Aceptar</Button>
  279. </DialogActions>
  280. </Dialog>
  281. {/* Dialog for copy odoo modules */}
  282. <Dialog open={showDialog === 'show-modules'} onClose={this.handleCloseDialog} fullScreen={true}>
  283. <DialogTitle>Seleccionar modulos</DialogTitle>
  284. <DialogContent>
  285. <DialogContentText>Seleccione los módulos que desea copiar/actualizar en un sistema desplegado.</DialogContentText>
  286. <FormControl margin='normal' fullWidth={true}>
  287. <InputLabel>Seleccionar el Sistema</InputLabel>
  288. <Select
  289. value={this.state.selectedOdoo}
  290. onChange={this.handleChangeOdooSystem}
  291. inputProps={{
  292. name: 'selectedOdoo'
  293. }}>
  294. {this.state.odoos.map(o =>
  295. <MenuItem key={o.id} value={o.name}>{o.name}</MenuItem>
  296. )}
  297. </Select>
  298. </FormControl>
  299. <div className={classes.transfer}>
  300. <div className={classes.transferPanels}>
  301. <Typography variant='title'>Módulos disponibles</Typography>
  302. <TextField type='search' placeholder='Buscar' fullWidth={true} margin='normal' onKeyUp={this.handleModulesSearch} />
  303. <div className={classes.transferModules}>
  304. <List>
  305. {this.state.modules.map((repo, index) =>
  306. <ListItem key={index}>
  307. <ListItemText primary={repo} />
  308. <ListItemSecondaryAction onClick={e => this.handleAddModule(index, e)}>
  309. <IconButton>
  310. <AddIcon />
  311. </IconButton>
  312. </ListItemSecondaryAction>
  313. </ListItem>
  314. )}
  315. </List>
  316. </div>
  317. </div>
  318. <div className={classes.transferPanels}>
  319. <Typography variant='title'>Módulos a copiar/actualizar</Typography>
  320. <div className={classes.transferModules}>
  321. <List>
  322. {this.state.modulesToInstall.map((toInstall, index) =>
  323. <ListItem key={index}>
  324. <ListItemText primary={toInstall} />
  325. <ListItemSecondaryAction onClick={e => this.handleRemoveModule(index, e)}>
  326. <IconButton>
  327. <RemoveIcon />
  328. </IconButton>
  329. </ListItemSecondaryAction>
  330. </ListItem>
  331. )}
  332. </List>
  333. </div>
  334. </div>
  335. </div>
  336. </DialogContent>
  337. <DialogActions>
  338. <Button color='primary' onClick={this.handleCloseDialog}>Cancelar</Button>
  339. <Button color='primary' onClick={this.handleAcceptDialog}>Aceptar</Button>
  340. </DialogActions>
  341. </Dialog>
  342. </Base>
  343. )
  344. }
  345. }
  346. /**
  347. *
  348. * @param {*} state
  349. * @param {*} props
  350. */
  351. const mapStateToProps = (state, props) => {
  352. return {
  353. containers: state.containers,
  354. repositories: state.repositories
  355. }
  356. }
  357. /**
  358. *
  359. * @param {*} dispatch
  360. * @param {*} props
  361. */
  362. const mapDispatchToProps = (dispatch, props) => ({
  363. /**
  364. *
  365. */
  366. loadData() {
  367. dispatch(get(`${REQUEST}?last`))
  368. },
  369. /**
  370. *
  371. */
  372. loadRepositories() {
  373. return dispatch(get(`${GIT}repositories/`))
  374. },
  375. /**
  376. *
  377. */
  378. loadContainers() {
  379. return dispatch(get(`${DOCKER}container/all/`))
  380. },
  381. /**
  382. *
  383. */
  384. createOdoo(name) {
  385. dispatch(post(`${ODOO}create/`, { name }))
  386. },
  387. /**
  388. *
  389. * @param {*} name
  390. * @param {*} modules
  391. */
  392. installModules(system, modules) {
  393. dispatch(post(`${ODOO}install_modules/`, {system, modules}))
  394. }
  395. })
  396. TasksList = withStyles(styles)(TasksList)
  397. export default connect(mapStateToProps, mapDispatchToProps)(TasksList)