ReplicaList.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 Location from '../../core/Location';
  18. import UserIcon from '../UserIcon';
  19. import NotificationIcon from '../NotificationIcon';
  20. import Moment from 'react-moment';
  21. import s from './ReplicaList.scss';
  22. import MigrationStore from '../../stores/MigrationStore';
  23. import MigrationActions from '../../actions/MigrationActions';
  24. import TextTruncate from 'react-text-truncate';
  25. import ProjectsDropdown from '../ProjectsDropdown';
  26. import MainList from '../MainList';
  27. import Helper from '../Helper';
  28. const title = 'Coriolis Replicas';
  29. const filters = [
  30. {
  31. field: "status",
  32. options: [
  33. { value: null, label: "All" },
  34. { value: "RUNNING", label: "Running" },
  35. { value: "ERROR", label: "Error" },
  36. { value: "COMPLETED", label: "Completed" }
  37. ]
  38. }
  39. ]
  40. const replicaActions = {
  41. execute_action: {
  42. label: "Execute",
  43. action: (item) => {
  44. MigrationActions.executeReplica(item)
  45. },
  46. confirm: false
  47. },
  48. delete_action: {
  49. label: "Delete",
  50. action: (item) => {
  51. MigrationActions.deleteReplica(item)
  52. },
  53. confirm: true
  54. }
  55. }
  56. class ReplicaList extends Reflux.Component {
  57. constructor(props) {
  58. super(props)
  59. this.store = MigrationStore;
  60. this.state = {
  61. replicas: null
  62. }
  63. this.renderItem = this.renderItem.bind(this)
  64. }
  65. static contextTypes = {
  66. onSetTitle: PropTypes.func.isRequired
  67. };
  68. componentWillMount() {
  69. super.componentWillMount.call(this)
  70. this.context.onSetTitle(title);
  71. MigrationActions.loadReplicas()
  72. }
  73. newMigration() {
  74. Location.push('/replicas/new')
  75. }
  76. replicaDetail(e, item) {
  77. Location.push('/replica/' + item.id + "/")
  78. }
  79. renderItem(item) {
  80. let count = 0
  81. if (item.executions.length) {
  82. item.tasks = item.executions[item.executions.length - 1].tasks
  83. }
  84. if (!item.tasks) {
  85. item.tasks = []
  86. }
  87. item.tasks.forEach((task) => {
  88. if (task.status != "COMPLETED") count++
  89. })
  90. let tasksRemaining = count + " out of " + item.tasks.length
  91. if (count == 0) {
  92. tasksRemaining = "-"
  93. }
  94. let lastExecution = null
  95. if (item.executions.length) {
  96. lastExecution = Helper.getTimeObject(item.executions[item.executions.length - 1].created_at)
  97. }
  98. return (
  99. <div className={"item " + (item.selected ? "selected" : "")} key={"replica_" + item.id}>
  100. <span className="cell cell-icon" onClick={(e) => this.replicaDetail(e, item)}>
  101. <div className={"icon " + item.type}></div>
  102. <span className="details">
  103. <TextTruncate line={1} truncateText="..." text={item.name} />
  104. <span className={s.migrationStatus + " status-pill " + item.status}>{item.status}</span>
  105. </span>
  106. </span>
  107. <span className="cell" onClick={(e) => this.replicaDetail(e, item)}>
  108. <div className={s.cloudImage + " icon small-cloud " + item.origin_endpoint_type}></div>
  109. <span className={s.chevronRight}></span>
  110. <div className={s.cloudImage + " icon small-cloud " + item.destination_endpoint_type}></div>
  111. </span>
  112. <span className={"cell " + s.composite} onClick={(e) => this.replicaDetail(e, item)}>
  113. <span className={s.label}>Last execution</span>
  114. <span className={s.value}>
  115. {lastExecution ? <Moment format="MMM Do YYYY HH:mm" date={lastExecution} /> : "-"}
  116. </span>
  117. </span>
  118. <span className={"cell " + s.composite} onClick={(e) => this.replicaDetail(e, item)}>
  119. <span className={s.label}>Tasks remaining</span>
  120. <span className={s.value}>{tasksRemaining}</span>
  121. </span>
  122. {/*<span className={"cell " + s.composite}>
  123. <span className={s.label}>Current instance</span>
  124. <span className={s.value}>{this.currentInstance(item)}</span>
  125. </span>*/}
  126. </div>
  127. )
  128. }
  129. currentInstance(migration) {
  130. let instance = "N/A"
  131. /*migration.vms.forEach((item) => {
  132. if (item.selected) {
  133. instance = item.name
  134. }
  135. })*/
  136. return instance
  137. }
  138. refreshList() {
  139. MigrationActions.loadReplicas()
  140. }
  141. render() {
  142. return (
  143. <div className={s.root}>
  144. <div className={s.container}>
  145. <div className={s.pageHeader}>
  146. <div className={s.top}>
  147. <h1>{title}</h1>
  148. <div className={s.topActions}>
  149. <ProjectsDropdown />
  150. <button onClick={this.newMigration}>New</button>
  151. <UserIcon />
  152. <NotificationIcon />
  153. </div>
  154. </div>
  155. </div>
  156. <MainList
  157. items={this.state.replicas}
  158. actions={replicaActions}
  159. itemName="replica"
  160. renderItem={this.renderItem}
  161. filters={filters}
  162. refresh={this.refreshList}
  163. />
  164. </div>
  165. </div>
  166. );
  167. }
  168. }
  169. export default withStyles(ReplicaList, s);