ReplicaDetailsContent.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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 from 'react'
  15. import styled from 'styled-components'
  16. import { observer } from 'mobx-react'
  17. import scheduleStore from '@src/stores/ScheduleStore'
  18. import Button from '@src/components/ui/Button'
  19. import DetailsNavigation from '@src/components/modules/NavigationModule/DetailsNavigation'
  20. import MainDetails from '@src/components/modules/TransferModule/MainDetails'
  21. import Executions from '@src/components/modules/TransferModule/Executions'
  22. import Schedule from '@src/components/modules/TransferModule/Schedule'
  23. import type { Instance } from '@src/@types/Instance'
  24. import type { Endpoint, StorageBackend } from '@src/@types/Endpoint'
  25. import type { Execution, ExecutionTasks } from '@src/@types/Execution'
  26. import type { Network } from '@src/@types/Network'
  27. import type { Field } from '@src/@types/Field'
  28. import type { Schedule as ScheduleType } from '@src/@types/Schedule'
  29. import { ReplicaItemDetails } from '@src/@types/MainItem'
  30. import { MinionPool } from '@src/@types/MinionPool'
  31. import { ThemeProps } from '@src/components/Theme'
  32. const Wrapper = styled.div<any>`
  33. display: flex;
  34. justify-content: center;
  35. `
  36. const Buttons = styled.div<any>`
  37. display: flex;
  38. justify-content: space-between;
  39. margin-top: 24px;
  40. `
  41. const ButtonColumn = styled.div<any>`
  42. display: flex;
  43. flex-direction: column;
  44. button {
  45. margin-top: 16px;
  46. &:first-child {
  47. margin-top: 0;
  48. }
  49. }
  50. `
  51. const DetailsBody = styled.div<any>`
  52. ${ThemeProps.exactWidth(ThemeProps.contentWidth)}
  53. `
  54. const NavigationItems = [
  55. {
  56. label: 'Replica',
  57. value: '',
  58. }, {
  59. label: 'Executions',
  60. value: 'executions',
  61. }, {
  62. label: 'Schedule',
  63. value: 'schedule',
  64. },
  65. ]
  66. type TimezoneValue = 'utc' | 'local'
  67. type Props = {
  68. item?: ReplicaItemDetails | null,
  69. itemId: string
  70. endpoints: Endpoint[],
  71. sourceSchema: Field[],
  72. sourceSchemaLoading: boolean,
  73. destinationSchema: Field[],
  74. destinationSchemaLoading: boolean,
  75. networks: Network[],
  76. instancesDetails: Instance[],
  77. instancesDetailsLoading: boolean,
  78. scheduleStore: typeof scheduleStore,
  79. page: string,
  80. detailsLoading: boolean,
  81. executions: Execution[],
  82. executionsLoading: boolean,
  83. executionsTasksLoading: boolean,
  84. executionsTasks: ExecutionTasks[],
  85. minionPools: MinionPool[]
  86. storageBackends: StorageBackend[]
  87. onExecutionChange: (executionId: string) => void,
  88. onCancelExecutionClick: (execution: Execution | null, force?: boolean) => void,
  89. onDeleteExecutionClick: (execution: Execution | null) => void,
  90. onExecuteClick: () => void,
  91. onCreateMigrationClick: () => void,
  92. onDeleteReplicaClick: () => void,
  93. onAddScheduleClick: (schedule: ScheduleType) => void,
  94. onScheduleChange: (scheduleId: string | null, data: ScheduleType, forceSave?: boolean) => void,
  95. onScheduleRemove: (scheduleId: string | null) => void,
  96. onScheduleSave: (schedule: ScheduleType) => void,
  97. }
  98. type State = {
  99. timezone: TimezoneValue,
  100. }
  101. @observer
  102. class ReplicaDetailsContent extends React.Component<Props, State> {
  103. state: State = {
  104. timezone: 'local',
  105. }
  106. getLastExecution() {
  107. return this.props.item && this.props.item.executions && this.props.item.executions.length
  108. && this.props.item.executions[this.props.item.executions.length - 1]
  109. }
  110. getStatus() {
  111. const lastExecution = this.getLastExecution()
  112. return lastExecution && lastExecution.status
  113. }
  114. isEndpointMissing() {
  115. const originEndpoint = this.props.endpoints
  116. .find(e => this.props.item && e.id === this.props.item.origin_endpoint_id)
  117. const targetEndpoint = this.props.endpoints
  118. .find(e => this.props.item && e.id === this.props.item.destination_endpoint_id)
  119. return Boolean(!originEndpoint || !targetEndpoint)
  120. }
  121. handleTimezoneChange(timezone: TimezoneValue) {
  122. this.setState({ timezone })
  123. }
  124. renderBottomControls() {
  125. return (
  126. <Buttons>
  127. <ButtonColumn>
  128. <Button
  129. secondary
  130. disabled={this.getStatus() === 'RUNNING'}
  131. onClick={this.props.onExecuteClick}
  132. >Execute Replica
  133. </Button>
  134. <Button
  135. primary
  136. disabled={this.isEndpointMissing()}
  137. onClick={this.props.onCreateMigrationClick}
  138. >Create Migration
  139. </Button>
  140. </ButtonColumn>
  141. <ButtonColumn>
  142. <Button
  143. alert
  144. hollow
  145. onClick={this.props.onDeleteReplicaClick}
  146. >Delete Replica
  147. </Button>
  148. </ButtonColumn>
  149. </Buttons>
  150. )
  151. }
  152. renderMainDetails() {
  153. if (this.props.page !== '') {
  154. return null
  155. }
  156. return (
  157. <MainDetails
  158. item={this.props.item}
  159. storageBackends={this.props.storageBackends}
  160. minionPools={this.props.minionPools}
  161. sourceSchema={this.props.sourceSchema}
  162. sourceSchemaLoading={this.props.sourceSchemaLoading}
  163. destinationSchema={this.props.destinationSchema}
  164. destinationSchemaLoading={this.props.destinationSchemaLoading}
  165. instancesDetails={this.props.instancesDetails}
  166. instancesDetailsLoading={this.props.instancesDetailsLoading}
  167. loading={this.props.detailsLoading}
  168. endpoints={this.props.endpoints}
  169. networks={this.props.networks}
  170. bottomControls={this.renderBottomControls()}
  171. />
  172. )
  173. }
  174. renderExecutions() {
  175. if (this.props.page !== 'executions') {
  176. return null
  177. }
  178. return (
  179. <Executions
  180. executions={this.props.executions}
  181. executionsTasks={this.props.executionsTasks}
  182. onCancelExecutionClick={this.props.onCancelExecutionClick}
  183. onDeleteExecutionClick={this.props.onDeleteExecutionClick}
  184. onExecuteClick={this.props.onExecuteClick}
  185. loading={this.props.executionsLoading || this.props.detailsLoading}
  186. onChange={this.props.onExecutionChange}
  187. tasksLoading={this.props.executionsTasksLoading}
  188. instancesDetails={this.props.instancesDetails}
  189. />
  190. )
  191. }
  192. renderSchedule() {
  193. if (this.props.page !== 'schedule') {
  194. return null
  195. }
  196. return (
  197. <Schedule
  198. schedules={this.props.scheduleStore.schedules}
  199. unsavedSchedules={this.props.scheduleStore.unsavedSchedules}
  200. adding={this.props.scheduleStore.adding}
  201. loading={this.props.scheduleStore.loading}
  202. onAddScheduleClick={this.props.onAddScheduleClick}
  203. onChange={this.props.onScheduleChange}
  204. onRemove={this.props.onScheduleRemove}
  205. onSaveSchedule={this.props.onScheduleSave}
  206. timezone={this.state.timezone}
  207. onTimezoneChange={timezone => { this.handleTimezoneChange(timezone) }}
  208. savingIds={this.props.scheduleStore.savingIds}
  209. enablingIds={this.props.scheduleStore.enablingIds}
  210. deletingIds={this.props.scheduleStore.deletingIds}
  211. />
  212. )
  213. }
  214. render() {
  215. return (
  216. <Wrapper>
  217. <DetailsNavigation
  218. items={NavigationItems}
  219. selectedValue={this.props.page}
  220. itemId={this.props.itemId}
  221. itemType="replica"
  222. />
  223. <DetailsBody>
  224. {this.renderMainDetails()}
  225. {this.renderExecutions()}
  226. {this.renderSchedule()}
  227. </DetailsBody>
  228. </Wrapper>
  229. )
  230. }
  231. }
  232. export default ReplicaDetailsContent