ReplicaView.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. import React, { PropTypes } from 'react';
  15. import Reflux from 'reflux';
  16. import withStyles from 'isomorphic-style-loader/lib/withStyles';
  17. import s from './ReplicaView.scss';
  18. import Header from '../Header';
  19. import Link from '../Link';
  20. import MigrationStore from '../../stores/MigrationStore';
  21. import MigrationActions from '../../actions/MigrationActions';
  22. import LoadingIcon from '../LoadingIcon';
  23. import TextTruncate from 'react-text-truncate';
  24. import Location from '../../core/Location';
  25. import ConfirmationDialog from '../ConfirmationDialog'
  26. class ReplicaView extends Reflux.Component {
  27. static propTypes = {
  28. type: PropTypes.string
  29. }
  30. static contextTypes = {
  31. onSetTitle: PropTypes.func.isRequired,
  32. };
  33. constructor(props) {
  34. super(props)
  35. this.store = MigrationStore
  36. this.state = {
  37. title: 'Coriolis: View Replica',
  38. confirmationDialog: {
  39. visible: false,
  40. message: "Are you sure?",
  41. onConfirm: null,
  42. onCancel: null
  43. }
  44. }
  45. }
  46. componentWillMount() {
  47. super.componentWillMount.call(this)
  48. MigrationActions.setReplica(this.props.replicaId)
  49. }
  50. componentDidMount() {
  51. this.context.onSetTitle(this.state.title);
  52. }
  53. executeReplica() {
  54. let item = this.state.replicas.filter(replica => replica.id == this.props.replicaId)[0]
  55. MigrationActions.executeReplica(item)
  56. }
  57. goBack() {
  58. Location.push('/replicas')
  59. }
  60. onMigrationActionsChange(option) {
  61. let item = this.state.replicas.filter(replica => replica.id == this.props.replicaId)[0]
  62. switch (option.value) {
  63. case "delete":
  64. MigrationActions.deleteReplica(item)
  65. Location.push('/cloud-endpoints')
  66. break
  67. case "start":
  68. MigrationActions.executeReplica(item)
  69. break
  70. default:
  71. break
  72. }
  73. }
  74. currentReplica(replicaId) {
  75. if (this.state.replicas) {
  76. return this.state.replicas.filter(replica => replica.id == replicaId)[0]
  77. } else {
  78. return null
  79. }
  80. }
  81. render() {
  82. let item = this.currentReplica(this.props.replicaId)
  83. let title = "Edit"
  84. if (item) {
  85. title = "Edit Replica"
  86. let disabled = item.executions.length && item.executions[item.executions.length - 1].status != "COMPLETED"
  87. if (item.executions.length == 0) {
  88. disabled = true
  89. }
  90. let itemStatus = item.status
  91. if (item.executions.length) {
  92. itemStatus = item.executions[item.executions.length - 1].status
  93. }
  94. return (
  95. <div className={s.root}>
  96. <Header title={title} linkUrl="/replicas" />
  97. <div className={s.migrationHead}>
  98. <div className={s.container}>
  99. <div className="backBtn" onClick={(e) => this.goBack(e)}></div>
  100. <div className={s.migrationTypeImg + ' icon ' + item.type + "-large"}></div>
  101. <div className={s.migrationInfo}>
  102. <h2>
  103. <TextTruncate line={1} truncateText="..." text={item.name} />
  104. </h2>
  105. <div className={s.migrationStats}>
  106. <span className={s.migrationType + " " + item.type}>{item.type}</span>
  107. <span className={s.migrationStatus + " " + itemStatus + " status-pill"}>{itemStatus}</span>
  108. </div>
  109. </div>
  110. <div className={s.migrationActions}>
  111. <div>
  112. <button
  113. className="gray"
  114. disabled={item.status === "RUNNING"}
  115. onClick={(e) => this.executeReplica(e)}>
  116. Execute Now
  117. </button>
  118. </div>
  119. </div>
  120. </div>
  121. </div>
  122. <div className={s.container}>
  123. {item ? (
  124. <div className={s.sidebar}>
  125. <Link
  126. to={"/replica/" + item.id + "/"}
  127. className={this.props.type == 'detail' ? "active" : ""}
  128. >Replica</Link>
  129. <Link
  130. to={"/replica/executions/" + item.id + "/"}
  131. className={this.props.type == 'tasks' ? "active" : ""}
  132. >Executions</Link>
  133. <Link
  134. to={"/replica/schedule/" + item.id + "/"}
  135. className={this.props.type == 'schedule' ? "active" : ""}
  136. >Schedule</Link>
  137. </div>
  138. ) : ""}
  139. <div className={s.content}>
  140. {React.cloneElement(this.props.children, { replica: item })}
  141. </div>
  142. </div>
  143. <ConfirmationDialog
  144. visible={this.state.confirmationDialog.visible}
  145. message={this.state.confirmationDialog.message}
  146. onConfirm={(e) => this.state.confirmationDialog.onConfirm(e)}
  147. onCancel={(e) => this.state.confirmationDialog.onCancel(e)}
  148. />
  149. </div>
  150. )
  151. } else {
  152. return (<div className={s.root}>
  153. <div className={s.container}>
  154. <LoadingIcon />
  155. </div>
  156. </div>)
  157. }
  158. }
  159. }
  160. export default withStyles(ReplicaView, s);