/* Copyright (C) 2017 Cloudbase Solutions SRL This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import * as React from "react"; import { observer } from "mobx-react"; import styled from "styled-components"; import Button from "@src/components/ui/Button"; import FieldInput from "@src/components/ui/FieldInput"; import ToggleButtonBar from "@src/components/ui/ToggleButtonBar"; import type { Field } from "@src/@types/Field"; import { ThemeProps } from "@src/components/Theme"; import LabelDictionary from "@src/utils/LabelDictionary"; import assessmentImage from "./images/assessment.svg"; const Wrapper = styled.div` padding: 48px 32px 32px 32px; display: flex; flex-direction: column; align-items: center; min-height: 0; `; const Image = styled.div` width: 96px; height: 96px; background: url("${assessmentImage}") center no-repeat; `; const ToggleButtonBarStyled = styled(ToggleButtonBar)` margin-top: 48px; `; const Fields = styled.div` display: flex; margin-top: 32px; flex-direction: column; overflow: auto; width: 100%; min-height: 0; `; const FieldStyled = styled(FieldInput)` ${ThemeProps.exactWidth(`${ThemeProps.inputSizes.large.width}px`)} margin-bottom: 16px; `; const Row = styled.div` display: flex; flex-shrink: 0; justify-content: space-between; `; const Buttons = styled.div` display: flex; justify-content: space-between; width: 100%; margin-top: 32px; `; const generalFields = [ { name: "use_replica", type: "boolean", }, { name: "separate_vm", type: "boolean", }, ]; const replicaFields = [ { name: "shutdown_instances", type: "boolean", }, ]; const migrationFields = [ { name: "skip_os_morphing", type: "boolean", }, ]; type Props = { onCancelClick: () => void; onExecuteClick: (fieldValues: { [prop: string]: any }) => void; executeButtonDisabled: boolean; replicaSchema: Field[]; migrationSchema: Field[]; onResizeUpdate?: (scrollableRef: HTMLElement, scrollOffset?: number) => void; }; type State = { fieldValues: { [prop: string]: any }; showAdvancedOptions: boolean; }; @observer class AssessmentMigrationOptions extends React.Component { state: State = { fieldValues: { separate_vm: true, use_replica: false, shutdown_instances: false, skip_os_morphing: false, }, showAdvancedOptions: false, }; // scrollableRef: HTMLElement | undefined | null getFieldValue(fieldName: string) { if (this.state.fieldValues[fieldName] != null) { return this.state.fieldValues[fieldName]; } return null; } getObjectFieldValue(fieldName: string, propName: string) { return ( this.state.fieldValues[fieldName] && this.state.fieldValues[fieldName][propName] ); } handleValueChange(fieldName: string, value: any) { this.setState(prevState => { const fieldValues = { ...prevState.fieldValues }; if (value != null) { fieldValues[fieldName] = value; } else { delete fieldValues[fieldName]; } return { fieldValues }; }); } // UNSAFE_componentDidUpdate(_: Props, prevState: State) { // if (prevState.showAdvancedOptions !== this.state.showAdvancedOptions // && this.props.onResizeUpdate && this.scrollableRef) { // this.props.onResizeUpdate(this.scrollableRef) // } // } handleObjectValueChange(fieldName: string, propName: string, value: any) { this.setState(prevState => { const fieldValues = { ...prevState.fieldValues }; if (!fieldValues[fieldName]) { fieldValues[fieldName] = {}; } fieldValues[fieldName][propName] = value; return { fieldValues }; }); } renderFields() { let fields: any = generalFields; const useReplica = this.getFieldValue("use_replica"); const skipFields = [ "location", "resource_group", "network_map", "storage_map", "vm_size", "worker_size", ]; // eslint-disable-next-line no-shadow const cleanup = (cleanupFields: any[]) => cleanupFields .filter((f: { name: string }) => !skipFields.find(n => n === f.name)) .map((f: { type: string; nullableBoolean: boolean }) => { if (f.type === "boolean") { // eslint-disable-next-line no-param-reassign f.nullableBoolean = true; } return { ...f }; }); if (useReplica) { fields = [...fields, ...replicaFields]; if (this.state.showAdvancedOptions) { fields = [...fields, ...cleanup(this.props.replicaSchema)]; } } else { fields = [...fields, ...migrationFields]; if (this.state.showAdvancedOptions) { fields = [...fields, ...cleanup(this.props.migrationSchema)]; } } const sortPriority: any = { boolean: 1, string: 2, object: 3, }; fields.sort((a: any, b: any) => { if (sortPriority[a.type] && sortPriority[b.type]) { return sortPriority[a.type] - sortPriority[b.type]; } if (sortPriority[a.type]) { return -1; } if (sortPriority[b.type]) { return 1; } return a.name.localeCompare(b.name); }); const rows: JSX.Element[] = []; let lastField: JSX.Element; fields.forEach((field: any, index: number) => { let additionalProps; if (field.type === "object" && field.properties) { additionalProps = { valueCallback: (callbackField: { name: string }) => this.getObjectFieldValue(field.name, callbackField.name), onChange: (value: any, callbackField: { name: string }) => { const propName = callbackField.name.substr( callbackField.name.lastIndexOf("/") + 1 ); this.handleObjectValueChange(field.name, propName, value); }, properties: field.properties.map((p: any) => ({ ...p, required: false, })), }; } else { const value = this.getFieldValue(field.name); additionalProps = { value, // eslint-disable-next-line no-shadow onChange: (changeValue: any) => { this.handleValueChange(field.name, changeValue); }, type: field.type, }; } const currentField = ( ); const pushRow = (field1: React.ReactNode, field2?: React.ReactNode) => { rows.push( {field1} {field2} ); }; if (index === fields.length - 1 && index % 2 === 0) { pushRow(currentField); } else if (index % 2 !== 0) { pushRow(lastField, currentField); } else { lastField = currentField; } }); return ( // { this.scrollableRef = ref }}> {rows} ); } render() { return ( { this.setState({ showAdvancedOptions: item.value === "advanced" }); }} /> {this.renderFields()} ); } } export default AssessmentMigrationOptions;