ContentPlugin.jsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. // @flow
  15. import React from 'react'
  16. import styled from 'styled-components'
  17. import ToggleButtonBar from '../../../components/atoms/ToggleButtonBar'
  18. import type { Field } from '../../../types/Field'
  19. import { Wrapper, Fields, FieldStyled, Row } from '../default/ContentPlugin'
  20. const ToggleButtonBarStyled = styled(ToggleButtonBar) `
  21. margin-top: 16px;
  22. `
  23. type Props = {
  24. connectionInfoSchema: Field[],
  25. validation: { valid: boolean, validation: { message: string } },
  26. invalidFields: string[],
  27. getFieldValue: (field: ?Field) => any,
  28. handleFieldChange: (field: ?Field, value: any) => void,
  29. disabled: boolean,
  30. cancelButtonText: string,
  31. validating: boolean,
  32. onRef: (contentPlugin: any) => void,
  33. onResizeUpdate: (scrollOfset: number) => void,
  34. scrollableRef: (ref: HTMLElement) => void,
  35. }
  36. type State = {
  37. useAdvancedOptions: boolean,
  38. }
  39. class ContentPlugin extends React.Component<Props, State> {
  40. constructor() {
  41. super()
  42. this.state = {
  43. useAdvancedOptions: false,
  44. }
  45. }
  46. componentDidMount() {
  47. this.props.onRef(this)
  48. }
  49. componentDidUpdate(prevProps: Props, prevState: State) {
  50. if (prevState.useAdvancedOptions !== this.state.useAdvancedOptions) {
  51. this.props.onResizeUpdate(0)
  52. }
  53. }
  54. componentWillUnmount() {
  55. this.props.onRef(undefined)
  56. }
  57. getApiVersion(): number {
  58. return this.props.getFieldValue(this.props.connectionInfoSchema.find(n => n.name === 'identity_api_version'))
  59. }
  60. getFieldValue(field: ?Field) {
  61. let fieldValue = this.props.getFieldValue(field)
  62. if (fieldValue) {
  63. return fieldValue
  64. }
  65. let getInputChoiceValue = (fieldBaseName: string): string => {
  66. let id = this.props.getFieldValue(this.props.connectionInfoSchema.find(n => n.name === `${fieldBaseName}_id`))
  67. let previouslySelected = this.previouslySelectedChoices.find(f => f === `${fieldBaseName}_id`)
  68. if (id || previouslySelected) {
  69. if (!previouslySelected) this.previouslySelectedChoices.push(`${fieldBaseName}_id`)
  70. return `${fieldBaseName}_id`
  71. }
  72. return `${fieldBaseName}_name`
  73. }
  74. if (field && field.name === 'user_domain') {
  75. return getInputChoiceValue('user_domain')
  76. }
  77. if (field && field.name === 'project_domain') {
  78. return getInputChoiceValue('project_domain')
  79. }
  80. return fieldValue
  81. }
  82. handleAdvancedOptionsToggle(useAdvancedOptions: boolean) {
  83. this.setState({ useAdvancedOptions })
  84. }
  85. previouslySelectedChoices: string[] = []
  86. findInvalidFields = () => {
  87. let inputChoices = ['user_domain', 'project_domain']
  88. const invalidFields = this.props.connectionInfoSchema.filter(field => {
  89. if (field.required) {
  90. let value = this.getFieldValue(field)
  91. return !value
  92. }
  93. let inputChoice = inputChoices.find(c => c === field.name)
  94. if (inputChoice && this.getApiVersion() > 2) {
  95. let selectionValue = this.getFieldValue(this.props.connectionInfoSchema.find(f => f.name === inputChoice))
  96. let itemValue = this.getFieldValue(this.props.connectionInfoSchema.find(f => f.name === selectionValue))
  97. return !itemValue
  98. }
  99. return false
  100. }).map(f => f.name)
  101. return invalidFields
  102. }
  103. filterSimpleAdvanced(): Field[] {
  104. let extraAdvancedFields = ['description', 'glance_api_version', 'identity_api_version']
  105. if (this.getApiVersion() > 2) {
  106. extraAdvancedFields = extraAdvancedFields.concat(['user_domain', 'project_domain'])
  107. }
  108. let ignoreFields = ['user_domain_id', 'project_domain_id', 'user_domain_name', 'project_domain_name']
  109. return this.props.connectionInfoSchema.filter(f => !ignoreFields.find(i => i === f.name)).filter(field => {
  110. if (this.state.useAdvancedOptions) {
  111. return true
  112. }
  113. return field.required || extraAdvancedFields.find(fieldName => field.name === fieldName)
  114. })
  115. }
  116. renderSimpleAdvancedToggle() {
  117. return (
  118. <ToggleButtonBarStyled
  119. items={[{ label: 'Simple', value: 'simple' }, { label: 'Advanced', value: 'advanced' }]}
  120. selectedValue={this.state.useAdvancedOptions ? 'advanced' : 'simple'}
  121. onChange={item => { this.handleAdvancedOptionsToggle(item.value === 'advanced') }}
  122. />
  123. )
  124. }
  125. renderFields() {
  126. const rows = []
  127. let lastField
  128. let fields = this.filterSimpleAdvanced()
  129. fields.forEach((field, i) => {
  130. const currentField = (
  131. <FieldStyled
  132. {...field}
  133. required={field.required || (this.getApiVersion() > 2 ? field.name === 'user_domain' || field.name === 'project_domain' : false)}
  134. large
  135. disabled={this.props.disabled}
  136. password={field.name === 'password'}
  137. highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
  138. value={this.getFieldValue(field)}
  139. onChange={value => { this.props.handleFieldChange(field, value) }}
  140. getFieldValue={fieldName => this.getFieldValue(this.props.connectionInfoSchema.find(n => n.name === fieldName))}
  141. onFieldChange={(fieldName, fieldValue) => { this.props.handleFieldChange(this.props.connectionInfoSchema.find(n => n.name === fieldName), fieldValue) }}
  142. />
  143. )
  144. if (i % 2 !== 0) {
  145. rows.push((
  146. <Row key={field.name}>
  147. {lastField}
  148. {currentField}
  149. </Row>
  150. ))
  151. } else if (i === this.props.connectionInfoSchema.length - 1) {
  152. rows.push((
  153. <Row key={field.name}>
  154. {currentField}
  155. </Row>
  156. ))
  157. }
  158. lastField = currentField
  159. })
  160. return (
  161. <Fields innerRef={ref => { this.props.scrollableRef(ref) }}>
  162. {rows}
  163. </Fields>
  164. )
  165. }
  166. render() {
  167. return (
  168. <Wrapper>
  169. {this.renderSimpleAdvancedToggle()}
  170. {this.renderFields()}
  171. </Wrapper>
  172. )
  173. }
  174. }
  175. export default ContentPlugin