MinionEndpointModal.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. Copyright (C) 2020 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 { observer } from 'mobx-react'
  16. import styled from 'styled-components'
  17. import { CSSTransitionGroup } from 'react-transition-group'
  18. import Modal from '@src/components/ui/Modal/Modal'
  19. import { Providers, ProviderTypes } from '@src/@types/Providers'
  20. import { Endpoint } from '@src/@types/Endpoint'
  21. import StatusImage from '@src/components/ui/StatusComponents/StatusImage/StatusImage'
  22. import Switch from '@src/components/ui/Switch/Switch'
  23. import { providerTypes } from '@src/constants'
  24. import EndpointLogos from '@src/components/modules/EndpointModule/EndpointLogos/EndpointLogos'
  25. import Dropdown from '@src/components/ui/Dropdowns/Dropdown/Dropdown'
  26. import Button from '@src/components/ui/Button/Button'
  27. import { ThemePalette } from '@src/components/Theme'
  28. const Wrapper = styled.div``
  29. const LoadingWrapper = styled.div`
  30. margin: 96px;
  31. display: flex;
  32. align-items: center;
  33. justify-content: center;
  34. flex-direction: column;
  35. `
  36. const ContentWrapper = styled.div`
  37. padding: 48px;
  38. > span {
  39. display: flex;
  40. justify-content: center;
  41. margin-left: -24px;
  42. transition: all 250ms ease-out;
  43. > div {
  44. margin-left: 24px;
  45. }
  46. }
  47. `
  48. const NoEndpoints = styled.div`
  49. padding: 64px;
  50. display: flex;
  51. align-items: center;
  52. justify-content: center;
  53. flex-direction: column;
  54. `
  55. const NoEndpointsMessage = styled.div`
  56. text-align: center;
  57. margin-top: 48px;
  58. `
  59. const ProviderWrapper = styled.div`
  60. display: flex;
  61. align-items: center;
  62. justify-content: center;
  63. flex-direction: column;
  64. &.providers-group-transition-leave {
  65. opacity: 1;
  66. }
  67. &.providers-group-transition-leave-active {
  68. opacity: 0.01;
  69. transition: opacity 250ms ease-out;
  70. }
  71. &.providers-group-transition-enter {
  72. opacity: 0.01;
  73. }
  74. &.providers-group-transition-enter-active {
  75. opacity: 1;
  76. transition: opacity 250ms ease-out;
  77. }
  78. `
  79. const ButtonWrapper = styled.div`
  80. display: flex;
  81. align-items: center;
  82. justify-content: space-between;
  83. margin: 16px 32px 32px 32px;
  84. `
  85. const PoolPlatformWrapper = styled.div`
  86. display: flex;
  87. flex-direction: column;
  88. align-items: center;
  89. margin: 32px 0 64px 0;
  90. `
  91. const PoolPlatformOptions = styled.div`
  92. display: flex;
  93. align-items: center;
  94. `
  95. const PoolPlatformOption = styled.div``
  96. const SwitchWrapper = styled.div`
  97. margin: 0 16px;
  98. `
  99. type Props = {
  100. providers: Providers | null
  101. endpoints: Endpoint[]
  102. loading: boolean
  103. onRequestClose: () => void
  104. onSelectEndpoint: (endpoint: Endpoint, platform: 'source' | 'destination') => void
  105. }
  106. type State = {
  107. selectedEndpoint: Endpoint | null
  108. platform: 'source' | 'destination'
  109. }
  110. @observer
  111. class MinionEndpointModal extends React.Component<Props, State> {
  112. state: State = {
  113. selectedEndpoint: null,
  114. platform: 'source',
  115. }
  116. handleNextClick() {
  117. this.props.onSelectEndpoint(this.state.selectedEndpoint!, this.state.platform)
  118. }
  119. renderNoEndpoints() {
  120. return (
  121. <NoEndpoints>
  122. <StatusImage status="ERROR" />
  123. <NoEndpointsMessage>
  124. Please create a Coriolis Endpoint with Minion Pool support
  125. before creating a Coriolis Minion Pool.
  126. </NoEndpointsMessage>
  127. </NoEndpoints>
  128. )
  129. }
  130. renderPoolPlatform() {
  131. return (
  132. <PoolPlatformWrapper>
  133. <PoolPlatformOptions>
  134. <PoolPlatformOption>Source Minion Pool</PoolPlatformOption>
  135. <SwitchWrapper>
  136. <Switch
  137. big
  138. checked={this.state.platform === 'destination'}
  139. checkedColor={ThemePalette.primary}
  140. uncheckedColor={ThemePalette.primary}
  141. onChange={value => {
  142. this.setState({
  143. platform: value ? 'destination' : 'source',
  144. })
  145. }}
  146. />
  147. </SwitchWrapper>
  148. <PoolPlatformOption>Destination Minion Pool</PoolPlatformOption>
  149. </PoolPlatformOptions>
  150. </PoolPlatformWrapper>
  151. )
  152. }
  153. renderContent() {
  154. if (!this.props.providers) {
  155. return this.renderNoEndpoints()
  156. }
  157. const availableProviders = Object.keys(this.props.providers).filter((name: any) => {
  158. const providerName = name as ProviderTypes
  159. const providerType = this.state.platform === 'source' ? providerTypes.SOURCE_MINION_POOL : providerTypes.DESTINATION_MINION_POOL
  160. const types = this.props.providers?.[providerName].types.indexOf(providerType)
  161. return types && types > -1
  162. })
  163. const availableEndpoints = this.props.endpoints
  164. .filter(e => availableProviders.indexOf(e.type) > -1)
  165. if (availableProviders.length === 0 || availableEndpoints.length === 0) {
  166. return this.renderNoEndpoints()
  167. }
  168. return (
  169. <ContentWrapper>
  170. <CSSTransitionGroup
  171. transitionName="providers-group-transition"
  172. transitionLeave
  173. transitionEnter
  174. transitionLeaveTimeout={250}
  175. transitionEnterTimeout={250}
  176. >
  177. {availableProviders.map(providerName => (
  178. <ProviderWrapper key={providerName}>
  179. <EndpointLogos
  180. height={128}
  181. endpoint={providerName}
  182. style={{ marginBottom: '16px' }}
  183. />
  184. <Dropdown
  185. items={this.props.endpoints.filter(e => e.type === providerName)}
  186. valueField="id"
  187. labelField="name"
  188. noSelectionMessage="Choose an endpoint"
  189. centered
  190. selectedItem={this.state.selectedEndpoint?.type === providerName ? this.state.selectedEndpoint : null}
  191. onChange={endpoint => { this.setState({ selectedEndpoint: endpoint }) }}
  192. />
  193. </ProviderWrapper>
  194. ))}
  195. </CSSTransitionGroup>
  196. </ContentWrapper>
  197. )
  198. }
  199. renderLoading() {
  200. return (
  201. <LoadingWrapper>
  202. <StatusImage loading />
  203. </LoadingWrapper>
  204. )
  205. }
  206. render() {
  207. return (
  208. <Modal
  209. isOpen
  210. title="Choose Minion Pool Endpoint"
  211. onRequestClose={this.props.onRequestClose}
  212. >
  213. <Wrapper>
  214. {!this.props.loading ? this.renderContent() : null}
  215. {this.props.loading ? this.renderLoading() : null}
  216. {!this.props.loading ? this.renderPoolPlatform() : null}
  217. <ButtonWrapper>
  218. <Button secondary onClick={this.props.onRequestClose}>Cancel</Button>
  219. <Button
  220. primary
  221. disabled={!this.state.selectedEndpoint}
  222. onClick={() => { this.handleNextClick() }}
  223. >
  224. Next
  225. </Button>
  226. </ButtonWrapper>
  227. </Wrapper>
  228. </Modal>
  229. )
  230. }
  231. }
  232. export default MinionEndpointModal