|
|
@@ -66,7 +66,8 @@ const GroupNameBar = styled.div<any>`
|
|
|
const GroupFields = styled.div<any>`
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
- margin-top: ${props => (props.name === "Deployment options" ? "32px" : "16px")};
|
|
|
+ margin-top: ${props =>
|
|
|
+ props.name === "Deployment options" ? "32px" : "16px"};
|
|
|
`;
|
|
|
const Column = styled.div<any>`
|
|
|
margin-top: -16px;
|
|
|
@@ -78,299 +79,304 @@ const FieldInputStyled = styled(FieldInput)`
|
|
|
`;
|
|
|
|
|
|
export const shouldRenderField = (field: Field) =>
|
|
|
- (field.type !== "array" ||
|
|
|
- (field.enum && field.enum.length && field.enum.length > 0)) &&
|
|
|
- (field.type !== "object" || field.properties);
|
|
|
+ (field.type !== "array" ||
|
|
|
+ (field.enum && field.enum.length && field.enum.length > 0)) &&
|
|
|
+ (field.type !== "object" || field.properties);
|
|
|
|
|
|
type FieldRender = {
|
|
|
- field: Field;
|
|
|
- component: React.ReactNode;
|
|
|
- column: number;
|
|
|
+ field: Field;
|
|
|
+ component: React.ReactNode;
|
|
|
+ column: number;
|
|
|
};
|
|
|
|
|
|
type Props = {
|
|
|
- options: Field[];
|
|
|
- wizardType: string;
|
|
|
- layout?: "page" | "modal";
|
|
|
- data?: { [prop: string]: any } | null;
|
|
|
- fieldWidth?: number;
|
|
|
- getFieldValue?: (
|
|
|
- fieldName: string,
|
|
|
- defaultValue: any,
|
|
|
- parentFieldName: string | undefined
|
|
|
- ) => any;
|
|
|
- onChange: (field: Field, value: any, parentFieldName?: string) => void;
|
|
|
- onScrollableRef?: (ref: HTMLElement) => void;
|
|
|
+ options: Field[];
|
|
|
+ wizardType: string;
|
|
|
+ layout?: "page" | "modal";
|
|
|
+ data?: { [prop: string]: any } | null;
|
|
|
+ fieldWidth?: number;
|
|
|
+ getFieldValue?: (
|
|
|
+ fieldName: string,
|
|
|
+ defaultValue: any,
|
|
|
+ parentFieldName: string | undefined
|
|
|
+ ) => any;
|
|
|
+ onChange: (field: Field, value: any, parentFieldName?: string) => void;
|
|
|
+ onScrollableRef?: (ref: HTMLElement) => void;
|
|
|
};
|
|
|
type State = {
|
|
|
- executionOptions: { [prop: string]: any } | null;
|
|
|
+ executionOptions: { [prop: string]: any } | null;
|
|
|
};
|
|
|
|
|
|
@observer
|
|
|
class WizardExecuteOptions extends React.Component<Props, State> {
|
|
|
- state: State = {
|
|
|
- executionOptions: null,
|
|
|
- };
|
|
|
-
|
|
|
- getDefaultSimpleFieldsSchema() {
|
|
|
- const fieldsSchema: Field[] = [];
|
|
|
- if (this.props.wizardType === "replica-execute" || this.props.wizardType === "migration-execute") {
|
|
|
- fieldsSchema.push({
|
|
|
- name: "execute_now",
|
|
|
- type: "boolean",
|
|
|
- default: true,
|
|
|
- nullableBoolean: false,
|
|
|
- description:
|
|
|
- "When enabled, the transfer will be executed immediately after the options are configured.",
|
|
|
-
|
|
|
- });
|
|
|
- fieldsSchema.push({
|
|
|
- name: "auto_deploy",
|
|
|
- type: "boolean",
|
|
|
- default: false,
|
|
|
- nullableBoolean: false,
|
|
|
- description:
|
|
|
- "When enabled, the transfer will automatically deploy the instances on the destination cloud after the transfer is complete.",
|
|
|
- });
|
|
|
-
|
|
|
- fieldsSchema.push({
|
|
|
- name: "shutdown_instances",
|
|
|
- type: "boolean",
|
|
|
- default: false,
|
|
|
- nullableBoolean: false,
|
|
|
- description:
|
|
|
- "When enabled, the instances will be shut down before the transfer is executed.",
|
|
|
- });
|
|
|
- }
|
|
|
- else if (this.props.wizardType === "edit-deploy") {
|
|
|
- fieldsSchema.push({
|
|
|
- name: "clone_disks",
|
|
|
- type: "boolean",
|
|
|
- label: "Clone Disks",
|
|
|
- nullableBoolean: false,
|
|
|
- default: true,
|
|
|
- description: "When enabled, the disks will be cloned during the deployment."
|
|
|
- })
|
|
|
-
|
|
|
- fieldsSchema.push({
|
|
|
- name: "skip_os_morphing",
|
|
|
- type: "boolean",
|
|
|
- label: "Skip OS Morphing",
|
|
|
- nullableBoolean: false,
|
|
|
- default: false,
|
|
|
- description: "When enabled, OS Morphing will be skipped during the deployment."
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- return fieldsSchema;
|
|
|
+ state: State = {
|
|
|
+ executionOptions: null,
|
|
|
+ };
|
|
|
+
|
|
|
+ getDefaultSimpleFieldsSchema() {
|
|
|
+ const fieldsSchema: Field[] = [];
|
|
|
+ if (
|
|
|
+ this.props.wizardType === "replica-execute" ||
|
|
|
+ this.props.wizardType === "migration-execute"
|
|
|
+ ) {
|
|
|
+ fieldsSchema.push({
|
|
|
+ name: "execute_now",
|
|
|
+ type: "boolean",
|
|
|
+ default: true,
|
|
|
+ nullableBoolean: false,
|
|
|
+ description:
|
|
|
+ "When enabled, the transfer will be executed immediately after the options are configured.",
|
|
|
+ });
|
|
|
+ fieldsSchema.push({
|
|
|
+ name: "auto_deploy",
|
|
|
+ type: "boolean",
|
|
|
+ default: false,
|
|
|
+ nullableBoolean: false,
|
|
|
+ description:
|
|
|
+ "When enabled, the transfer will automatically deploy the instances on the destination cloud after the transfer is complete.",
|
|
|
+ });
|
|
|
+
|
|
|
+ fieldsSchema.push({
|
|
|
+ name: "shutdown_instances",
|
|
|
+ type: "boolean",
|
|
|
+ default: false,
|
|
|
+ nullableBoolean: false,
|
|
|
+ description:
|
|
|
+ "When enabled, the instances will be shut down before the transfer is executed.",
|
|
|
+ });
|
|
|
+ } else if (this.props.wizardType === "edit-deploy") {
|
|
|
+ fieldsSchema.push({
|
|
|
+ name: "clone_disks",
|
|
|
+ type: "boolean",
|
|
|
+ label: "Clone Disks",
|
|
|
+ nullableBoolean: false,
|
|
|
+ default: true,
|
|
|
+ description:
|
|
|
+ "When enabled, the disks will be cloned during the deployment.",
|
|
|
+ });
|
|
|
+
|
|
|
+ fieldsSchema.push({
|
|
|
+ name: "skip_os_morphing",
|
|
|
+ type: "boolean",
|
|
|
+ label: "Skip OS Morphing",
|
|
|
+ nullableBoolean: false,
|
|
|
+ default: false,
|
|
|
+ description:
|
|
|
+ "When enabled, OS Morphing will be skipped during the deployment.",
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- generateGroups(fields: FieldRender[]) {
|
|
|
- let groups: Array<{ fields: FieldRender[]; name?: string }> = [{ fields }];
|
|
|
-
|
|
|
- if (this.props.wizardType === "replica-execute" || this.props.wizardType === "migration-execute") {
|
|
|
- const deploymentFieldNames = deploymentFields.map(f => f.name);
|
|
|
- const deploymentFieldsInUse = fields.filter(f =>
|
|
|
- deploymentFieldNames.includes(f.field.name)
|
|
|
- );
|
|
|
- const additionalDeploymentFields = deploymentFields.filter(
|
|
|
- f => !fields.some(field => field.field.name === f.name)
|
|
|
- ).map((field) => ({
|
|
|
- column: fields.length % 2,
|
|
|
- component: this.renderOptionsField({
|
|
|
- ...field,
|
|
|
- default: field.defaultValue,
|
|
|
- }),
|
|
|
- field: {
|
|
|
- ...field,
|
|
|
- default: field.defaultValue,
|
|
|
- },
|
|
|
- }));
|
|
|
- if (deploymentFieldsInUse.length > 0 || additionalDeploymentFields.length > 0) {
|
|
|
- groups.push({
|
|
|
- name: "Deployment options",
|
|
|
- fields: [
|
|
|
- ...deploymentFieldsInUse.map((f, i) => ({ ...f, column: i % 2 })),
|
|
|
- ...additionalDeploymentFields
|
|
|
- ],
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
+ return fieldsSchema;
|
|
|
+ }
|
|
|
|
|
|
- fields.forEach(f => {
|
|
|
- if (f.field.groupName) {
|
|
|
- groups[0].fields = groups[0].fields
|
|
|
- ? groups[0].fields.filter(gf => gf.field.name !== f.field.name)
|
|
|
- : [];
|
|
|
-
|
|
|
- const group = groups.find(g => g.name && g.name === f.field.groupName);
|
|
|
- if (!group) {
|
|
|
- groups.push({
|
|
|
- name: f.field.groupName,
|
|
|
- fields: [f],
|
|
|
- });
|
|
|
- } else {
|
|
|
- group.fields.push(f);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
+ generateGroups(fields: FieldRender[]) {
|
|
|
+ const groups: Array<{ fields: FieldRender[]; name?: string }> = [
|
|
|
+ { fields },
|
|
|
+ ];
|
|
|
|
|
|
- return groups;
|
|
|
- }
|
|
|
-
|
|
|
- getFieldValue(
|
|
|
- fieldName: string,
|
|
|
- defaultValue: any,
|
|
|
- parentFieldName?: string
|
|
|
+ if (
|
|
|
+ this.props.wizardType === "replica-execute" ||
|
|
|
+ this.props.wizardType === "migration-execute"
|
|
|
) {
|
|
|
- if (this.props.getFieldValue) {
|
|
|
- return this.props.getFieldValue(fieldName, defaultValue, parentFieldName);
|
|
|
- }
|
|
|
+ const deploymentFieldNames = deploymentFields.map(f => f.name);
|
|
|
+ const deploymentFieldsInUse = fields.filter(f =>
|
|
|
+ deploymentFieldNames.includes(f.field.name)
|
|
|
+ );
|
|
|
+ const additionalDeploymentFields = deploymentFields
|
|
|
+ .filter(f => !fields.some(field => field.field.name === f.name))
|
|
|
+ .map(field => ({
|
|
|
+ column: fields.length % 2,
|
|
|
+ component: this.renderOptionsField({
|
|
|
+ ...field,
|
|
|
+ default: field.defaultValue,
|
|
|
+ }),
|
|
|
+ field: {
|
|
|
+ ...field,
|
|
|
+ default: field.defaultValue,
|
|
|
+ },
|
|
|
+ }));
|
|
|
+ if (
|
|
|
+ deploymentFieldsInUse.length > 0 ||
|
|
|
+ additionalDeploymentFields.length > 0
|
|
|
+ ) {
|
|
|
+ groups.push({
|
|
|
+ name: "Deployment options",
|
|
|
+ fields: [
|
|
|
+ ...deploymentFieldsInUse.map((f, i) => ({ ...f, column: i % 2 })),
|
|
|
+ ...additionalDeploymentFields,
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (!this.props.data) {
|
|
|
- return defaultValue;
|
|
|
+ fields.forEach(f => {
|
|
|
+ if (f.field.groupName) {
|
|
|
+ groups[0].fields = groups[0].fields
|
|
|
+ ? groups[0].fields.filter(gf => gf.field.name !== f.field.name)
|
|
|
+ : [];
|
|
|
+
|
|
|
+ const group = groups.find(g => g.name && g.name === f.field.groupName);
|
|
|
+ if (!group) {
|
|
|
+ groups.push({
|
|
|
+ name: f.field.groupName,
|
|
|
+ fields: [f],
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ group.fields.push(f);
|
|
|
}
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- if (parentFieldName) {
|
|
|
- if (
|
|
|
- this.props.data[parentFieldName] &&
|
|
|
- this.props.data[parentFieldName][fieldName] !== undefined
|
|
|
- ) {
|
|
|
- return this.props.data[parentFieldName][fieldName];
|
|
|
- }
|
|
|
- return defaultValue;
|
|
|
- }
|
|
|
+ return groups;
|
|
|
+ }
|
|
|
|
|
|
- if (!this.props.data || this.props.data[fieldName] === undefined) {
|
|
|
- return defaultValue;
|
|
|
- }
|
|
|
+ getFieldValue(
|
|
|
+ fieldName: string,
|
|
|
+ defaultValue: any,
|
|
|
+ parentFieldName?: string
|
|
|
+ ) {
|
|
|
+ if (this.props.getFieldValue) {
|
|
|
+ return this.props.getFieldValue(fieldName, defaultValue, parentFieldName);
|
|
|
+ }
|
|
|
|
|
|
- return this.props.data[fieldName];
|
|
|
+ if (!this.props.data) {
|
|
|
+ return defaultValue;
|
|
|
}
|
|
|
|
|
|
- renderOptionsField(field: Field) {
|
|
|
- let additionalProps;
|
|
|
- if (field.type === "object" && field.properties) {
|
|
|
- additionalProps = {
|
|
|
- valueCallback: (f: any) =>
|
|
|
- this.getFieldValue(f.name, f.default, field.name),
|
|
|
- onChange: (value: any, f: any) => {
|
|
|
- this.props.onChange(f, value, field.name);
|
|
|
- },
|
|
|
- properties: field.properties,
|
|
|
- };
|
|
|
- } else {
|
|
|
- additionalProps = {
|
|
|
- value: this.getFieldValue(field.name, field.default, field.groupName),
|
|
|
- onChange: (value: any) => {
|
|
|
- this.props.onChange(field, value);
|
|
|
- },
|
|
|
- };
|
|
|
- }
|
|
|
- return (
|
|
|
- <FieldInputStyled
|
|
|
- layout={this.props.layout || "page"}
|
|
|
- key={field.name}
|
|
|
- name={field.name}
|
|
|
- type={field.type}
|
|
|
- minimum={field.minimum}
|
|
|
- maximum={field.maximum}
|
|
|
- label={field.label || LabelDictionary.get(field.name)}
|
|
|
- description={field.description || LabelDictionary.getDescription(field.name)}
|
|
|
- password={field.name.toLowerCase().includes("password")}
|
|
|
- enum={field.enum}
|
|
|
- addNullValue
|
|
|
- required={field.required}
|
|
|
- width={this.props.fieldWidth || ThemeProps.inputSizes.wizard.width}
|
|
|
- nullableBoolean={field.nullableBoolean}
|
|
|
- disabled={field.disabled}
|
|
|
- // eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
- {...additionalProps}
|
|
|
- />
|
|
|
- );
|
|
|
+ if (parentFieldName) {
|
|
|
+ if (
|
|
|
+ this.props.data[parentFieldName] &&
|
|
|
+ this.props.data[parentFieldName][fieldName] !== undefined
|
|
|
+ ) {
|
|
|
+ return this.props.data[parentFieldName][fieldName];
|
|
|
+ }
|
|
|
+ return defaultValue;
|
|
|
}
|
|
|
|
|
|
- renderOptionsFields() {
|
|
|
- let fieldsSchema: Field[] = this.getDefaultSimpleFieldsSchema();
|
|
|
-
|
|
|
- const isRequired = (f: Field) =>
|
|
|
- f.required || f.properties?.some(p => p.required);
|
|
|
-
|
|
|
- const defaultFieldNames = fieldsSchema.map(f => f.name);
|
|
|
- const filteredOptions = this.props.options.filter(
|
|
|
- f => !defaultFieldNames.includes(f.name) && isRequired(f)
|
|
|
- );
|
|
|
-
|
|
|
- fieldsSchema = fieldsSchema.concat(filteredOptions);
|
|
|
-
|
|
|
- const nonNullableBooleans: string[] = fieldsSchema
|
|
|
- .filter(f => f.type === "boolean" && f.nullableBoolean === false)
|
|
|
- .map(f => f.name);
|
|
|
-
|
|
|
- let executeNowColumn: number;
|
|
|
- const fields: FieldRender[] = fieldsSchema
|
|
|
- .filter(f => shouldRenderField(f))
|
|
|
- .map((field, i) => {
|
|
|
- let column: number = i % 2;
|
|
|
- if (field.name === "execute_now") {
|
|
|
- executeNowColumn = column;
|
|
|
- }
|
|
|
- const usableField = toJS(field);
|
|
|
- if (
|
|
|
- field.type === "boolean" &&
|
|
|
- !nonNullableBooleans.find(name => name === field.name)
|
|
|
- ) {
|
|
|
- usableField.nullableBoolean = true;
|
|
|
- }
|
|
|
-
|
|
|
- return {
|
|
|
- column,
|
|
|
- component: this.renderOptionsField(usableField),
|
|
|
- field: usableField,
|
|
|
- };
|
|
|
- });
|
|
|
-
|
|
|
- const groups = this.generateGroups(fields);
|
|
|
- return (
|
|
|
- <Fields ref={this.props.onScrollableRef} layout={this.props.layout}>
|
|
|
- {groups.map((g, i) => {
|
|
|
- const getColumnInGroup = (field: any, fieldIndex: number) =>
|
|
|
- g.name ? fieldIndex % 2 : field.column;
|
|
|
- return (
|
|
|
- <Group key={g.name || 0}>
|
|
|
- {g.name ? (
|
|
|
- <GroupName>
|
|
|
- <GroupNameBar />
|
|
|
- <GroupNameText>{LabelDictionary.get(g.name)}</GroupNameText>
|
|
|
- <GroupNameBar />
|
|
|
- </GroupName>
|
|
|
- ) : null}
|
|
|
- <GroupFields>
|
|
|
- <Column left>
|
|
|
- {g.fields.map(
|
|
|
- (f, j) => getColumnInGroup(f, j) === 0 && f.component
|
|
|
- )}
|
|
|
- </Column>
|
|
|
- <Column right>
|
|
|
- {g.fields.map(
|
|
|
- (f, j) => getColumnInGroup(f, j) === 1 && f.component
|
|
|
- )}
|
|
|
- </Column>
|
|
|
- </GroupFields>
|
|
|
- </Group>
|
|
|
- );
|
|
|
- })}
|
|
|
- </Fields>
|
|
|
- );
|
|
|
+ if (!this.props.data || this.props.data[fieldName] === undefined) {
|
|
|
+ return defaultValue;
|
|
|
}
|
|
|
|
|
|
- render() {
|
|
|
- return (
|
|
|
- <Wrapper>
|
|
|
- {this.renderOptionsFields()}
|
|
|
- </Wrapper>
|
|
|
- );
|
|
|
+ return this.props.data[fieldName];
|
|
|
+ }
|
|
|
+
|
|
|
+ renderOptionsField(field: Field) {
|
|
|
+ let additionalProps;
|
|
|
+ if (field.type === "object" && field.properties) {
|
|
|
+ additionalProps = {
|
|
|
+ valueCallback: (f: any) =>
|
|
|
+ this.getFieldValue(f.name, f.default, field.name),
|
|
|
+ onChange: (value: any, f: any) => {
|
|
|
+ this.props.onChange(f, value, field.name);
|
|
|
+ },
|
|
|
+ properties: field.properties,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ additionalProps = {
|
|
|
+ value: this.getFieldValue(field.name, field.default, field.groupName),
|
|
|
+ onChange: (value: any) => {
|
|
|
+ this.props.onChange(field, value);
|
|
|
+ },
|
|
|
+ };
|
|
|
}
|
|
|
+ return (
|
|
|
+ <FieldInputStyled
|
|
|
+ layout={this.props.layout || "page"}
|
|
|
+ key={field.name}
|
|
|
+ name={field.name}
|
|
|
+ type={field.type}
|
|
|
+ minimum={field.minimum}
|
|
|
+ maximum={field.maximum}
|
|
|
+ label={field.label || LabelDictionary.get(field.name)}
|
|
|
+ description={
|
|
|
+ field.description || LabelDictionary.getDescription(field.name)
|
|
|
+ }
|
|
|
+ password={field.name.toLowerCase().includes("password")}
|
|
|
+ enum={field.enum}
|
|
|
+ addNullValue
|
|
|
+ required={field.required}
|
|
|
+ width={this.props.fieldWidth || ThemeProps.inputSizes.wizard.width}
|
|
|
+ nullableBoolean={field.nullableBoolean}
|
|
|
+ disabled={field.disabled}
|
|
|
+ // eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
+ {...additionalProps}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ renderOptionsFields() {
|
|
|
+ let fieldsSchema: Field[] = this.getDefaultSimpleFieldsSchema();
|
|
|
+
|
|
|
+ const isRequired = (f: Field) =>
|
|
|
+ f.required || f.properties?.some(p => p.required);
|
|
|
+
|
|
|
+ const defaultFieldNames = fieldsSchema.map(f => f.name);
|
|
|
+ const filteredOptions = this.props.options.filter(
|
|
|
+ f => !defaultFieldNames.includes(f.name) && isRequired(f)
|
|
|
+ );
|
|
|
+
|
|
|
+ fieldsSchema = fieldsSchema.concat(filteredOptions);
|
|
|
+
|
|
|
+ const nonNullableBooleans: string[] = fieldsSchema
|
|
|
+ .filter(f => f.type === "boolean" && f.nullableBoolean === false)
|
|
|
+ .map(f => f.name);
|
|
|
+
|
|
|
+ const fields: FieldRender[] = fieldsSchema
|
|
|
+ .filter(f => shouldRenderField(f))
|
|
|
+ .map((field, i) => {
|
|
|
+ const column: number = i % 2;
|
|
|
+ const usableField = toJS(field);
|
|
|
+ if (
|
|
|
+ field.type === "boolean" &&
|
|
|
+ !nonNullableBooleans.find(name => name === field.name)
|
|
|
+ ) {
|
|
|
+ usableField.nullableBoolean = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ column,
|
|
|
+ component: this.renderOptionsField(usableField),
|
|
|
+ field: usableField,
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ const groups = this.generateGroups(fields);
|
|
|
+ return (
|
|
|
+ <Fields ref={this.props.onScrollableRef} layout={this.props.layout}>
|
|
|
+ {groups.map(g => {
|
|
|
+ const getColumnInGroup = (field: any, fieldIndex: number) =>
|
|
|
+ g.name ? fieldIndex % 2 : field.column;
|
|
|
+ return (
|
|
|
+ <Group key={g.name || 0}>
|
|
|
+ {g.name ? (
|
|
|
+ <GroupName>
|
|
|
+ <GroupNameBar />
|
|
|
+ <GroupNameText>{LabelDictionary.get(g.name)}</GroupNameText>
|
|
|
+ <GroupNameBar />
|
|
|
+ </GroupName>
|
|
|
+ ) : null}
|
|
|
+ <GroupFields>
|
|
|
+ <Column left>
|
|
|
+ {g.fields.map(
|
|
|
+ (f, j) => getColumnInGroup(f, j) === 0 && f.component
|
|
|
+ )}
|
|
|
+ </Column>
|
|
|
+ <Column right>
|
|
|
+ {g.fields.map(
|
|
|
+ (f, j) => getColumnInGroup(f, j) === 1 && f.component
|
|
|
+ )}
|
|
|
+ </Column>
|
|
|
+ </GroupFields>
|
|
|
+ </Group>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </Fields>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+ return <Wrapper>{this.renderOptionsFields()}</Wrapper>;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
export default WizardExecuteOptions;
|