From 213955aca25cbb0597d7e84725357822e2328963 Mon Sep 17 00:00:00 2001 From: David Resende Date: Wed, 13 Dec 2023 16:32:45 -0500 Subject: [PATCH 1/2] Convert Settings Replication Form to React --- .../validate-provider-credentials.jsx | 2 + .../settings-replication-form/helper.js | 43 ++++ .../settings-replication-form/index.jsx | 125 ++++++++++ .../settings-replication-form.schema.js | 219 ++++++++++++++++++ .../validate-subscription.jsx | 31 +++ .../pglogical_replication_form_controller.js | 179 +++++++------- .../packs/component-definitions-common.js | 2 + app/stylesheet/miq-data-table.scss | 6 + .../ops/_settings_replication_tab.html.haml | 2 + 9 files changed, 519 insertions(+), 90 deletions(-) create mode 100644 app/javascript/components/settings-replication-form/helper.js create mode 100644 app/javascript/components/settings-replication-form/index.jsx create mode 100644 app/javascript/components/settings-replication-form/settings-replication-form.schema.js create mode 100644 app/javascript/components/settings-replication-form/validate-subscription.jsx diff --git a/app/javascript/components/provider-form/validate-provider-credentials.jsx b/app/javascript/components/provider-form/validate-provider-credentials.jsx index 396b39de235..6f56def5408 100644 --- a/app/javascript/components/provider-form/validate-provider-credentials.jsx +++ b/app/javascript/components/provider-form/validate-provider-credentials.jsx @@ -12,6 +12,8 @@ const ValidateProviderCredentials = ({ ...props }) => { const asyncValidate = (fields, fieldNames) => new Promise((resolve, reject) => { const url = providerId ? `/api/providers/${providerId}` : '/api/providers'; const resource = pick(fields, fieldNames); + + console.log(resource); const updatedResource = trimFieldValue(resource); API.post(url, { action: 'verify_credentials', resource: updatedResource }).then(({ results: [result] = [], ...single }) => { diff --git a/app/javascript/components/settings-replication-form/helper.js b/app/javascript/components/settings-replication-form/helper.js new file mode 100644 index 00000000000..36a1cae728c --- /dev/null +++ b/app/javascript/components/settings-replication-form/helper.js @@ -0,0 +1,43 @@ +import React from 'react'; +import { useFieldApi, useFormApi } from '@@ddf'; +import { Button } from 'carbon-components-react'; +import MiqDataTable from '../miq-data-table'; + +export const SubscriptionsTableComponent = (props) => { + const { + rows, onCellClick, addButtonLabel, onButtonClick, + } = useFieldApi(props); + const formOptions = useFormApi(); + + return ( +
+ + + onCellClick(selectedRow, cellType, formOptions)} + /> +
+ ); +}; diff --git a/app/javascript/components/settings-replication-form/index.jsx b/app/javascript/components/settings-replication-form/index.jsx new file mode 100644 index 00000000000..89d0eb13569 --- /dev/null +++ b/app/javascript/components/settings-replication-form/index.jsx @@ -0,0 +1,125 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; + +import MiqFormRenderer from '@@ddf'; +import createSchema from './settings-replication-form.schema'; +import { SubscriptionsTableComponent } from './helper'; +import ValidateSubscription from './validate-subscription'; +import miqRedirectBack from '../../helpers/miq-redirect-back'; +import mapper from '../../forms/mappers/componentMapper'; +import { http } from '../../http_api'; + +const SettingsReplicationForm = ({ pglogicalReplicationFormId }) => { + const [{ + initialValues, subscriptions, form, replicationHelperText, isLoading, + }, setState] = useState({ isLoading: !!pglogicalReplicationFormId }); + const submitLabel = __('Save'); + + console.log(initialValues); + console.log(subscriptions); + + const componentMapper = { + ...mapper, + 'subscriptions-table': SubscriptionsTableComponent, + 'validate-subscription': ValidateSubscription, + }; + + // console.log(initialValues, form); + + useEffect(() => { + if (pglogicalReplicationFormId) { + miqSparkleOn(); + http.get(`/ops/pglogical_subscriptions_form_fields/${pglogicalReplicationFormId}`).then((response) => { + setState({ + initialValues: { + replication_type: response.replication_type, + subscriptions: response.subscriptions, + }, + subscriptions: response.subscriptions, + form: { + type: 'replication', + className: 'replication_form', + action: 'edit', + }, + replicationHelperText: '', + isLoading: false, + }); + }); + miqSparkleOff(); + } + }, [pglogicalReplicationFormId]); + + const onSubmit = (values) => { + if (form.type === 'subscription') { + const newSubscriptions = []; + + newSubscriptions.push({ + dbname: values.dbname, + host: values.host, + user: values.user, + password: values.password, + port: values.port, + }); + + setState((state) => ({ + ...state, + initialValues: { + replication_type: state.initialValues.replication_type, + subscriptions: state.initialValues.subscriptions, + }, + subscriptions: subscriptions.concat(newSubscriptions), + form: { + type: 'replication', + className: 'replication_form', + action: 'edit', + }, + })); + } else { + // Redirect to Settings -> Tasks + + /* http.post(`/ops/pglogical_save_subscriptions/${pglogicalReplicationFormId}?button=${'save'}`, submitData, { skipErrors: [400] }).then(() => { + const message = __('Order Request was Submitted'); + miqRedirectBack(message, 'success', '/miq_request/show_list?typ=service/'); + }).catch((err) => { + console.log(err); + }); */ + } + }; + + const onCancel = () => { + if (form.type === 'subscription') { + setState((state) => ({ + ...state, + form: { + type: 'replication', + className: 'replication_form', + action: 'edit', + }, + })); + } else { + const message = __('Dialog Cancelled'); + miqRedirectBack(message, 'warning', '/ops/explorer'); + } + }; + + return !isLoading && ( + + ); +}; + +SettingsReplicationForm.propTypes = { + pglogicalReplicationFormId: PropTypes.string, +}; +SettingsReplicationForm.defaultProps = { + pglogicalReplicationFormId: undefined, +}; + +export default SettingsReplicationForm; diff --git a/app/javascript/components/settings-replication-form/settings-replication-form.schema.js b/app/javascript/components/settings-replication-form/settings-replication-form.schema.js new file mode 100644 index 00000000000..8c5491a0963 --- /dev/null +++ b/app/javascript/components/settings-replication-form/settings-replication-form.schema.js @@ -0,0 +1,219 @@ +/* eslint-disable camelcase */ +import { componentTypes, validatorTypes } from '@@ddf'; + +const createSchema = (initialValues, subscriptions, form, replicationHelperText, setState) => { + // Creates the rows for the 'subscriptions-table' component + const createRows = () => { + const rows = []; + + subscriptions.forEach((value, index) => { + rows.push({ + id: index.toString(), + dbname: { text: value.dbname }, + host: { text: value.host }, + user: { text: value.user }, + password: { text: value.password }, + port: { text: value.port }, + backlog: { text: value.backlog ? value.backlog : '' }, + status: { text: value.status ? value.status : '' }, + provider_region: { text: value.provider_region || value.provider_region === 0 ? value.provider_region : '' }, + edit: { + is_button: true, + text: __('Update'), + kind: 'tertiary', + size: 'md', + callback: 'editSubscription', + }, + delete: { + is_button: true, + text: __('Delete'), + kind: 'danger', + size: 'md', + callback: 'deleteSubscription', + }, + }); + }); + + return rows; + }; + + const deleteSubscription = (selectedRow, cellType, formOptions) => { + subscriptions.splice(selectedRow.id, 1); + + setState((state) => ({ + ...state, + subscriptions, + })); + }; + + const editSubscription = (selectedRow) => { + setState((state) => ({ + ...state, + initialValues: { + ...state.initialValues, + dbname: selectedRow.cells[0].value, + host: selectedRow.cells[1].value, + user: selectedRow.cells[2].value, + password: selectedRow.cells[3].value, + port: selectedRow.cells[4].value, + }, + form: { + type: 'subscription', + className: 'subscription-form', + action: 'edit', + }, + })); + }; + + const replicationFields = ({ + fields: [ + { + component: componentTypes.SELECT, + id: 'replication_type', + name: 'replication_type', + label: __('Type'), + helperText: replicationHelperText, + onChange: (value) => { + let helperText; + + if (initialValues.replication_type === 'none' && value === 'none') { + helperText = __('No replication role has been set'); + } else if (initialValues.replication_type === 'remote' && value === 'none') { + helperText = __('Replication will be disabled for this region'); + } else if (initialValues.replication_type === 'global' && value === 'none') { + helperText = __('All current subscriptions will be removed'); + } else if (initialValues.replication_type === 'global' && value === 'remote') { + helperText = __('Changing to remote replication role will remove all current subscriptions'); + } + + setState((state) => ({ + ...state, + replicationHelperText: helperText, + })); + }, + options: [ + { + label: `<${_('None')}>`, + value: 'none', + }, + { + label: `Global`, + value: 'global', + }, + { + label: `Remote`, + value: 'remote', + }, + ], + }, + { + component: componentTypes.SUB_FORM, + name: 'subscriptions_section', + id: 'subscriptions_section', + condition: { + when: 'replication_type', + is: 'global', + }, + fields: [{ + component: 'subscriptions-table', + name: 'subscriptions-table', + id: 'subscriptions-table', + rows: createRows(), + onCellClick: (selectedRow, cellType, formOptions) => { + switch (selectedRow.callbackAction) { + case 'editSubscription': + editSubscription(selectedRow); + break; + case 'deleteSubscription': + deleteSubscription(selectedRow, cellType, formOptions); + break; + default: + break; + } + }, + addButtonLabel: __('Add Subscription'), + onButtonClick: (formOptions) => { + formOptions.change('dbname', ''); + formOptions.change('host', ''); + formOptions.change('user', ''); + formOptions.change('password', ''); + formOptions.change('port', ''); + setState((state) => ({ + ...state, + initialValues: { + replication_type: state.initialValues.replication_type, + subscriptions: state.initialValues.subscriptions, + }, + form: { + type: 'subscription', + className: 'subscription-form', + action: 'add', + }, + })); + }, + }], + }, + ], + }); + + const subscriptionFields = ({ + fields: [ + { + component: 'validate-subscription', + name: 'validate-sub', + id: 'validate-sub', + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + skipSubmit: true, + fields: [ + { + component: componentTypes.TEXT_FIELD, + name: 'dbname', + id: 'dbname', + label: __('Database'), + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + }, + { + component: componentTypes.TEXT_FIELD, + name: 'host', + id: 'host', + label: __('Host'), + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + }, + { + component: componentTypes.TEXT_FIELD, + name: 'user', + id: 'user', + label: __('Username'), + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + }, + { + component: componentTypes.TEXT_FIELD, + name: 'password', + id: 'password', + label: __('Password'), + type: 'password', + isReadOnly: form.action === 'edit', + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + }, + { + component: componentTypes.TEXT_FIELD, + name: 'port', + id: 'port', + label: __('Port'), + isRequired: true, + validate: [{ type: validatorTypes.REQUIRED }], + }, + ], + }, + ], + }); + + return form.type === 'subscription' ? subscriptionFields : replicationFields; +}; + +export default createSchema; diff --git a/app/javascript/components/settings-replication-form/validate-subscription.jsx b/app/javascript/components/settings-replication-form/validate-subscription.jsx new file mode 100644 index 00000000000..62f4dc17c4c --- /dev/null +++ b/app/javascript/components/settings-replication-form/validate-subscription.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { pick } from 'lodash'; + +import AsyncCredentials from '../async-credentials/async-credentials'; + +const ValidateSubscription = ({ ...props }) => { + const asyncValidate = (fields, fieldNames) => new Promise((resolve, reject) => { + const resource = pick(fields, fieldNames); + + resolve(); + + /* API.post('/api/ops/', { action: 'validate', resource }).then((response) => { + console.log(response); + }).catch(({ message }) => { console.log(message); return reject([__('Validation failed:'), message].join(' ')); }); */ + }); + + return ; +}; + +ValidateSubscription.propTypes = { + ...AsyncCredentials.propTypes, + asyncValidate: PropTypes.func, + validation: PropTypes.bool, +}; +ValidateSubscription.defaultProps = { + validation: true, + ...AsyncCredentials.defaultProps, +}; + +export default ValidateSubscription; diff --git a/app/javascript/oldjs/controllers/ops/pglogical_replication_form_controller.js b/app/javascript/oldjs/controllers/ops/pglogical_replication_form_controller.js index f3fc8963637..ac04240a621 100644 --- a/app/javascript/oldjs/controllers/ops/pglogical_replication_form_controller.js +++ b/app/javascript/oldjs/controllers/ops/pglogical_replication_form_controller.js @@ -1,5 +1,5 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', '$scope', 'pglogicalReplicationFormId', 'miqService', '$q', '$timeout', function($http, $scope, pglogicalReplicationFormId, miqService, $q, $timeout) { - var init = function() { + const init = function() { $scope.pglogicalReplicationModel = { replication_type: 'none', subscriptions: [], @@ -8,30 +8,30 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', }; $scope.formId = pglogicalReplicationFormId; $scope.afterGet = false; - $scope.modelCopy = angular.copy( $scope.pglogicalReplicationModel ); + $scope.modelCopy = angular.copy($scope.pglogicalReplicationModel); ManageIQ.angular.scope = $scope; $scope.model = 'pglogicalReplicationModel'; $scope.newRecord = false; miqService.sparkleOn(); - $http.get('/ops/pglogical_subscriptions_form_fields/' + pglogicalReplicationFormId) + $http.get(`/ops/pglogical_subscriptions_form_fields/${pglogicalReplicationFormId}`) .then(getPgLogicalFormData) .catch(miqService.handleFailure); }; - var pglogicalManageSubscriptionsButtonClicked = function(buttonName, serializeFields) { + const pglogicalManageSubscriptionsButtonClicked = function(buttonName, serializeFields) { miqService.sparkleOn(); - var url = '/ops/pglogical_save_subscriptions/' + pglogicalReplicationFormId + '?button=' + buttonName; - return $q.when(miqJqueryRequest(url, {data: serializeFields, complete: true})) - .then(function() { - $scope.modelCopy = angular.copy( $scope.pglogicalReplicationModel ); + const url = `/ops/pglogical_save_subscriptions/${pglogicalReplicationFormId}?button=${buttonName}`; + return $q.when(miqJqueryRequest(url, { data: serializeFields, complete: true })) + .then(() => { + $scope.modelCopy = angular.copy($scope.pglogicalReplicationModel); $scope.angularForm.$setPristine(); }); }; $scope.resetClicked = function() { - $scope.pglogicalReplicationModel = angular.copy( $scope.modelCopy ); + $scope.pglogicalReplicationModel = angular.copy($scope.modelCopy); $scope.angularForm.$setUntouched(true); $scope.angularForm.$setPristine(true); miqService.miqFlash('warn', __('All changes have been reset')); @@ -39,8 +39,8 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', $scope.saveClicked = function() { // remove existing subscriptions that have not changed before sending them up for save - var modified_subscriptions = $scope.pglogicalReplicationModel.subscriptions.filter(function(subscription, index) { - if (! subscription.id) { // new + const modified_subscriptions = $scope.pglogicalReplicationModel.subscriptions.filter((subscription, index) => { + if (!subscription.id) { // new return true; } @@ -55,18 +55,18 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', return false; }); pglogicalManageSubscriptionsButtonClicked('save', { - 'replication_type': $scope.pglogicalReplicationModel.replication_type, - 'subscriptions': modified_subscriptions, + replication_type: $scope.pglogicalReplicationModel.replication_type, + subscriptions: modified_subscriptions, }); }; // check if subscription values have been changed var subscriptionChanged = function(new_subscription, original_subscription) { - if (new_subscription.dbname === original_subscription.dbname && - new_subscription.host === original_subscription.host && - new_subscription.user === original_subscription.user && - new_subscription.password === original_subscription.password && - new_subscription.port === original_subscription.port) { + if (new_subscription.dbname === original_subscription.dbname + && new_subscription.host === original_subscription.host + && new_subscription.user === original_subscription.user + && new_subscription.password === original_subscription.password + && new_subscription.port === original_subscription.port) { return false; } return true; @@ -75,8 +75,8 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // replication type changed, show appropriate flash message $scope.replicationTypeChanged = function() { miqService.miqFlashClear(); - var original_value = $scope.modelCopy.replication_type; - var new_value = $scope.pglogicalReplicationModel.replication_type; + const original_value = $scope.modelCopy.replication_type; + const new_value = $scope.pglogicalReplicationModel.replication_type; if (original_value === 'none' && new_value === 'none') { miqService.miqFlash('warn', __('No replication role has been set')); } else if (original_value === 'remote' && new_value === 'none') { @@ -99,33 +99,33 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // add new subscription button pressed $scope.enableSubscriptionAdd = function() { $scope.pglogicalReplicationModel.updateEnabled = false; - $scope.pglogicalReplicationModel.addEnabled = true; - $scope.pglogicalReplicationModel.dbname = 'vmdb_production'; - $scope.pglogicalReplicationModel.host = ''; - $scope.pglogicalReplicationModel.user = ''; - $scope.pglogicalReplicationModel.password = ''; - $scope.pglogicalReplicationModel.port = '5432'; + $scope.pglogicalReplicationModel.addEnabled = true; + $scope.pglogicalReplicationModel.dbname = 'vmdb_production'; + $scope.pglogicalReplicationModel.host = ''; + $scope.pglogicalReplicationModel.user = ''; + $scope.pglogicalReplicationModel.password = ''; + $scope.pglogicalReplicationModel.port = '5432'; }; // update existing subscription button pressed $scope.enableSubscriptionUpdate = function(idx) { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; if (subscription.newRecord === true) { - $scope.pglogicalReplicationModel.s_index = idx; + $scope.pglogicalReplicationModel.s_index = idx; $scope.pglogicalReplicationModel.updateEnabled = true; - $scope.pglogicalReplicationModel.dbname = subscription.dbname; - $scope.pglogicalReplicationModel.host = subscription.host; - $scope.pglogicalReplicationModel.user = subscription.user; - $scope.pglogicalReplicationModel.password = subscription.password; - $scope.pglogicalReplicationModel.port = subscription.port; + $scope.pglogicalReplicationModel.dbname = subscription.dbname; + $scope.pglogicalReplicationModel.host = subscription.host; + $scope.pglogicalReplicationModel.user = subscription.user; + $scope.pglogicalReplicationModel.password = subscription.password; + $scope.pglogicalReplicationModel.port = subscription.port; } else if (confirm(__('An updated subscription must point to the same database with which it was originally created. Failure to do so will result in undefined behavior. Do you want to continue?'))) { - $scope.pglogicalReplicationModel.s_index = idx; + $scope.pglogicalReplicationModel.s_index = idx; $scope.pglogicalReplicationModel.updateEnabled = true; - $scope.pglogicalReplicationModel.dbname = subscription.dbname; - $scope.pglogicalReplicationModel.host = subscription.host; - $scope.pglogicalReplicationModel.user = subscription.user; - $scope.pglogicalReplicationModel.password = miqService.storedPasswordPlaceholder; - $scope.pglogicalReplicationModel.port = subscription.port; + $scope.pglogicalReplicationModel.dbname = subscription.dbname; + $scope.pglogicalReplicationModel.host = subscription.host; + $scope.pglogicalReplicationModel.user = subscription.user; + $scope.pglogicalReplicationModel.password = miqService.storedPasswordPlaceholder; + $scope.pglogicalReplicationModel.port = subscription.port; } }; @@ -141,11 +141,11 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', newRecord: true, }); } else { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; - subscription.dbname = $scope.pglogicalReplicationModel.dbname; - subscription.host = $scope.pglogicalReplicationModel.host; - subscription.user = $scope.pglogicalReplicationModel.user; - subscription.port = $scope.pglogicalReplicationModel.port; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + subscription.dbname = $scope.pglogicalReplicationModel.dbname; + subscription.host = $scope.pglogicalReplicationModel.host; + subscription.user = $scope.pglogicalReplicationModel.user; + subscription.port = $scope.pglogicalReplicationModel.port; } $scope.pglogicalReplicationModel.addEnabled = false; $scope.pglogicalReplicationModel.updateEnabled = false; @@ -158,7 +158,7 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // delete an existing subscription $scope.removeSubscription = function(idx) { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; if (subscription.newRecord === true) { $scope.pglogicalReplicationModel.subscriptions.splice(idx, 1); if (angular.equals($scope.pglogicalReplicationModel.subscriptions, $scope.modelCopy.subscriptions)) { @@ -172,36 +172,36 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // discard new subscription add $scope.discardSubscription = function(idx) { if (typeof idx === 'undefined') { - $scope.pglogicalReplicationModel.dbname = ''; - $scope.pglogicalReplicationModel.host = ''; - $scope.pglogicalReplicationModel.user = ''; - $scope.pglogicalReplicationModel.password = ''; - $scope.pglogicalReplicationModel.port = ''; + $scope.pglogicalReplicationModel.dbname = ''; + $scope.pglogicalReplicationModel.host = ''; + $scope.pglogicalReplicationModel.user = ''; + $scope.pglogicalReplicationModel.password = ''; + $scope.pglogicalReplicationModel.port = ''; $scope.pglogicalReplicationModel.addEnabled = false; } else { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; - var original_values = subscription; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + let original_values = subscription; if ($scope.modelCopy.subscriptions[idx]) { original_values = $scope.modelCopy.subscriptions[idx]; } $scope.pglogicalReplicationModel.updateEnabled = false; - subscription.dbname = original_values.dbname; - subscription.host = original_values.host; - subscription.user = original_values.user; + subscription.dbname = original_values.dbname; + subscription.host = original_values.host; + subscription.user = original_values.user; subscription.password = original_values.password; - subscription.port = original_values.port; + subscription.port = original_values.port; } $scope.angularForm.$setPristine(); }; // validate subscription, all required fields should have data $scope.subscriptionValid = function() { - if (typeof $scope.pglogicalReplicationModel.dbname !== 'undefined' && $scope.pglogicalReplicationModel.dbname !== '' && - typeof $scope.pglogicalReplicationModel.host !== 'undefined' && $scope.pglogicalReplicationModel.host !== '' && - typeof $scope.pglogicalReplicationModel.user !== 'undefined' && $scope.pglogicalReplicationModel.user !== '' && - typeof $scope.pglogicalReplicationModel.password !== 'undefined' && $scope.pglogicalReplicationModel.password !== '' + if (typeof $scope.pglogicalReplicationModel.dbname !== 'undefined' && $scope.pglogicalReplicationModel.dbname !== '' + && typeof $scope.pglogicalReplicationModel.host !== 'undefined' && $scope.pglogicalReplicationModel.host !== '' + && typeof $scope.pglogicalReplicationModel.user !== 'undefined' && $scope.pglogicalReplicationModel.user !== '' + && typeof $scope.pglogicalReplicationModel.password !== 'undefined' && $scope.pglogicalReplicationModel.password !== '' ) { return true; } @@ -209,19 +209,19 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', }; $scope.saveEnabled = function(form) { - var saveable = false; + let saveable = false; if ($scope.pglogicalReplicationModel.replication_type !== 'remote') { saveable = form.$dirty && form.$valid && !$scope.pglogicalReplicationModel.addEnabled && !$scope.pglogicalReplicationModel.updateEnabled; // also need to enable save button when an existing subscriptions was deleted - var subscriptions_changed = angular.equals($scope.pglogicalReplicationModel.subscriptions, $scope.modelCopy.subscriptions); + const subscriptions_changed = angular.equals($scope.pglogicalReplicationModel.subscriptions, $scope.modelCopy.subscriptions); - if ((saveable || !subscriptions_changed) && - $scope.pglogicalReplicationModel.replication_type === 'global' && - $scope.pglogicalReplicationModel.subscriptions.length >= 1) { + if ((saveable || !subscriptions_changed) + && $scope.pglogicalReplicationModel.replication_type === 'global' + && $scope.pglogicalReplicationModel.subscriptions.length >= 1) { return true; - } else if (saveable && - $scope.pglogicalReplicationModel.replication_type !== 'global' && - $scope.pglogicalReplicationModel.subscriptions.length === 0) { + } if (saveable + && $scope.pglogicalReplicationModel.replication_type !== 'global' + && $scope.pglogicalReplicationModel.subscriptions.length === 0) { return true; } @@ -240,30 +240,30 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // validate new/existing subscription $scope.validateSubscription = function(idx) { - var data = {}; + const data = {}; if (typeof idx === 'undefined') { data.dbname = $scope.pglogicalReplicationModel.dbname; - data.host = $scope.pglogicalReplicationModel.host; + data.host = $scope.pglogicalReplicationModel.host; data.user = $scope.pglogicalReplicationModel.user; data.password = $scope.pglogicalReplicationModel.password; - data.port = $scope.pglogicalReplicationModel.port; + data.port = $scope.pglogicalReplicationModel.port; } else { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; data.dbname = subscription.dbname; - data.host = subscription.host; + data.host = subscription.host; data.user = subscription.user; data.password = subscription.password; - data.port = subscription.port; + data.port = subscription.port; data.id = subscription.id; } miqService.sparkleOn(); - var url = '/ops/pglogical_validate_subscription'; + const url = '/ops/pglogical_validate_subscription'; miqService.miqAjaxButton(url, data); }; // cancel delete button should be displayed only if existing saved subscriptions were deleted $scope.showCancelDelete = function(idx) { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; // only show subscriptions in red if they were saved subscriptions and deleted in current edit session if (subscription.remove === true) { return true; @@ -273,21 +273,21 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', // put back subscription that was deleted into new subscriptions array $scope.cancelDelete = function(idx) { - var subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; + const subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; delete subscription.remove; }; $scope.showChanged = function(idx, fieldName) { - var original_values = $scope.modelCopy.subscriptions[idx]; - var subscription; + const original_values = $scope.modelCopy.subscriptions[idx]; + let subscription; // if updating a record use form fields to compare if ($scope.pglogicalReplicationModel.updateEnabled) { subscription = {}; - subscription.dbname = $scope.pglogicalReplicationModel.dbname; - subscription.host = $scope.pglogicalReplicationModel.host; - subscription.user = $scope.pglogicalReplicationModel.user; + subscription.dbname = $scope.pglogicalReplicationModel.dbname; + subscription.host = $scope.pglogicalReplicationModel.host; + subscription.user = $scope.pglogicalReplicationModel.user; subscription.password = $scope.pglogicalReplicationModel.password; - subscription.port = $scope.pglogicalReplicationModel.port; + subscription.port = $scope.pglogicalReplicationModel.port; } else { subscription = $scope.pglogicalReplicationModel.subscriptions[idx]; } @@ -299,17 +299,16 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', }; $scope.subscriptionInValidMessage = function() { - if ($scope.pglogicalReplicationModel.replication_type === 'global' && - ($scope.pglogicalReplicationModel.subscriptions.length === 0 || - ($scope.pglogicalReplicationModel.subscriptions.length === 1 && $scope.pglogicalReplicationModel.subscriptions[0].remove === true))) { + if ($scope.pglogicalReplicationModel.replication_type === 'global' + && ($scope.pglogicalReplicationModel.subscriptions.length === 0 + || ($scope.pglogicalReplicationModel.subscriptions.length === 1 && $scope.pglogicalReplicationModel.subscriptions[0].remove === true))) { return true; } return false; }; - function getPgLogicalFormData(response) { - var data = response.data; + const { data } = response; $scope.pglogicalReplicationModel.replication_type = data.replication_type; $scope.pglogicalReplicationModel.subscriptions = angular.copy(data.subscriptions); @@ -319,10 +318,10 @@ ManageIQ.angular.app.controller('pglogicalReplicationFormController', ['$http', } $scope.afterGet = true; - $scope.modelCopy = angular.copy( $scope.pglogicalReplicationModel ); + $scope.modelCopy = angular.copy($scope.pglogicalReplicationModel); miqService.sparkleOff(); - $timeout(function() { + $timeout(() => { $scope.codeMirrorRefresh = true; }); } diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js index e216038dca7..c98268c4e17 100644 --- a/app/javascript/packs/component-definitions-common.js +++ b/app/javascript/packs/component-definitions-common.js @@ -128,6 +128,7 @@ import SettingsCompanyCategories from '../components/settings-company-categories import SettingsCompanyTags from '../components/settings-company-tags'; import SettingsCompanyTagsEntryForm from '../components/settings-company-tags-entry-form'; import SettingsLabelTagMapping from '../components/settings-label-tag-mapping'; +import SettingsReplicationForm from '../components/settings-replication-form'; import SettingsTasksForm from '../components/settings-tasks-form'; import SettingsTimeProfileForm from '../components/settings-time-profile-form'; import SettingsZone from '../components/settings-zone'; @@ -300,6 +301,7 @@ ManageIQ.component.addReact('SettingsCompanyCategories', SettingsCompanyCategori ManageIQ.component.addReact('SettingsCompanyTags', SettingsCompanyTags); ManageIQ.component.addReact('SettingsCompanyTagsEntryForm', SettingsCompanyTagsEntryForm); ManageIQ.component.addReact('SettingsLabelTagMapping', SettingsLabelTagMapping); +ManageIQ.component.addReact('SettingsReplicationForm', SettingsReplicationForm); ManageIQ.component.addReact('SettingsTasksForm', SettingsTasksForm); ManageIQ.component.addReact('SettingsTimeProfileForm', SettingsTimeProfileForm); ManageIQ.component.addReact('SettingsZone', SettingsZone); diff --git a/app/stylesheet/miq-data-table.scss b/app/stylesheet/miq-data-table.scss index 7a5c18d3573..b4f5309ac95 100644 --- a/app/stylesheet/miq-data-table.scss +++ b/app/stylesheet/miq-data-table.scss @@ -295,6 +295,12 @@ table.miq_preview { } } +.subscriptions-table { + .subscription-add { + margin-bottom: 16px; + } +} + .header-button { width: 100px !important; } diff --git a/app/views/ops/_settings_replication_tab.html.haml b/app/views/ops/_settings_replication_tab.html.haml index d96bafa7d05..867dcbbbd44 100644 --- a/app/views/ops/_settings_replication_tab.html.haml +++ b/app/views/ops/_settings_replication_tab.html.haml @@ -1,4 +1,6 @@ - if @sb[:active_tab] == "settings_replication" + #tab_div + = react('SettingsReplicationForm', :pglogicalReplicationFormId => 'new') - @angular_form = true %form.form-horizontal#form_div{"name" => "angularForm", From 3cd6c6c6f8b30b64ae0b7c1fd006067065583dd5 Mon Sep 17 00:00:00 2001 From: David Resende Date: Fri, 16 Feb 2024 15:12:35 -0500 Subject: [PATCH 2/2] temp --- .../components/miq-data-table/index.jsx | 2 +- .../validate-provider-credentials.jsx | 1 - .../settings-replication-form/helper.js | 71 ++++----- .../settings-replication-form/index.jsx | 143 +++++++++++++++--- .../settings-replication-form.schema.js | 57 ++----- .../subscriptions-table.jsx | 48 ++++++ 6 files changed, 216 insertions(+), 106 deletions(-) create mode 100644 app/javascript/components/settings-replication-form/subscriptions-table.jsx diff --git a/app/javascript/components/miq-data-table/index.jsx b/app/javascript/components/miq-data-table/index.jsx index 7dbbe5a3d9d..6341b91ec30 100644 --- a/app/javascript/components/miq-data-table/index.jsx +++ b/app/javascript/components/miq-data-table/index.jsx @@ -89,7 +89,7 @@ const MiqDataTable = ({ /** Function to render the header cells. */ const renderHeaders = (getHeaderProps) => (headers.map((header) => { const { sortHeader, sortDirection } = headerSortingData(header); - let isSortable = true; + let isSortable = sortable; if (header.header.split('_')[0] === DefaultKey) { isSortable = false; } diff --git a/app/javascript/components/provider-form/validate-provider-credentials.jsx b/app/javascript/components/provider-form/validate-provider-credentials.jsx index 6f56def5408..e7c83ec3651 100644 --- a/app/javascript/components/provider-form/validate-provider-credentials.jsx +++ b/app/javascript/components/provider-form/validate-provider-credentials.jsx @@ -13,7 +13,6 @@ const ValidateProviderCredentials = ({ ...props }) => { const url = providerId ? `/api/providers/${providerId}` : '/api/providers'; const resource = pick(fields, fieldNames); - console.log(resource); const updatedResource = trimFieldValue(resource); API.post(url, { action: 'verify_credentials', resource: updatedResource }).then(({ results: [result] = [], ...single }) => { diff --git a/app/javascript/components/settings-replication-form/helper.js b/app/javascript/components/settings-replication-form/helper.js index 36a1cae728c..791da04621c 100644 --- a/app/javascript/components/settings-replication-form/helper.js +++ b/app/javascript/components/settings-replication-form/helper.js @@ -1,43 +1,34 @@ -import React from 'react'; -import { useFieldApi, useFormApi } from '@@ddf'; -import { Button } from 'carbon-components-react'; -import MiqDataTable from '../miq-data-table'; +// Creates the rows for the 'subscriptions-table' component +export const createRows = (subscriptions) => { + const rows = []; -export const SubscriptionsTableComponent = (props) => { - const { - rows, onCellClick, addButtonLabel, onButtonClick, - } = useFieldApi(props); - const formOptions = useFormApi(); + subscriptions.forEach((value, index) => { + rows.push({ + id: index.toString(), + dbname: { text: value.dbname }, + host: { text: value.host }, + user: { text: value.user }, + password: { text: value.password }, + port: { text: value.port }, + backlog: { text: value.backlog ? value.backlog : '' }, + status: { text: value.status ? value.status : '' }, + provider_region: { text: value.provider_region || value.provider_region === 0 ? value.provider_region : '' }, + edit: { + is_button: true, + text: __('Update'), + kind: 'tertiary', + size: 'md', + callback: 'editSubscription', + }, + delete: { + is_button: true, + text: __('Delete'), + kind: 'danger', + size: 'md', + callback: 'deleteSubscription', + }, + }); + }); - return ( -
- - - onCellClick(selectedRow, cellType, formOptions)} - /> -
- ); + return rows; }; diff --git a/app/javascript/components/settings-replication-form/index.jsx b/app/javascript/components/settings-replication-form/index.jsx index 89d0eb13569..8b206aba95e 100644 --- a/app/javascript/components/settings-replication-form/index.jsx +++ b/app/javascript/components/settings-replication-form/index.jsx @@ -2,8 +2,10 @@ import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import MiqFormRenderer from '@@ddf'; +// import { Button } from 'carbon-components-react'; +// import MiqDataTable from '../miq-data-table'; import createSchema from './settings-replication-form.schema'; -import { SubscriptionsTableComponent } from './helper'; +import { SubscriptionsTableComponent } from './subscriptions-table'; import ValidateSubscription from './validate-subscription'; import miqRedirectBack from '../../helpers/miq-redirect-back'; import mapper from '../../forms/mappers/componentMapper'; @@ -51,29 +53,58 @@ const SettingsReplicationForm = ({ pglogicalReplicationFormId }) => { const onSubmit = (values) => { if (form.type === 'subscription') { - const newSubscriptions = []; - - newSubscriptions.push({ - dbname: values.dbname, - host: values.host, - user: values.user, - password: values.password, - port: values.port, - }); + if (form.action === 'add') { + const newSubscriptions = []; - setState((state) => ({ - ...state, - initialValues: { - replication_type: state.initialValues.replication_type, - subscriptions: state.initialValues.subscriptions, - }, - subscriptions: subscriptions.concat(newSubscriptions), - form: { - type: 'replication', - className: 'replication_form', - action: 'edit', - }, - })); + newSubscriptions.push({ + dbname: values.dbname, + host: values.host, + user: values.user, + password: values.password, + port: values.port, + }); + + setState((state) => ({ + ...state, + initialValues: { + replication_type: state.initialValues.replication_type, + subscriptions: state.initialValues.subscriptions, + }, + subscriptions: subscriptions.concat(newSubscriptions), + form: { + type: 'replication', + className: 'replication_form', + action: 'edit', + }, + })); + } else if (form.action === 'edit') { + let modifiedSubscriptions = []; + modifiedSubscriptions = modifiedSubscriptions.concat(subscriptions); + + const editedSub = { + dbname: values.dbname, + host: values.host, + password: values.password, + port: values.port, + user: values.user, + }; + + modifiedSubscriptions[initialValues.subId] = editedSub; + + setState((state) => ({ + ...state, + initialValues: { + replication_type: state.initialValues.replication_type, + subscriptions: state.initialValues.subscriptions, + }, + subscriptions: modifiedSubscriptions, + form: { + type: 'replication', + className: 'replication_form', + action: 'edit', + }, + })); + } } else { // Redirect to Settings -> Tasks @@ -86,6 +117,17 @@ const SettingsReplicationForm = ({ pglogicalReplicationFormId }) => { } }; + /* const onReset = () => { + setEnforced(() => ({ ...initialValues.enforced })); + setValues(() => ({ ...initialValues.values })); + setDisabled(true); + setChanged(true); + setInvalid(() => ({ ...initialValues.invalid })); + // eslint-disable-next-line no-return-assign + Array.from(document.querySelectorAll('.quota-table-input')).forEach((input, index) => input.value = initialValues.values[index]); + add_flash(__('All changes have been reset'), 'warn'); + }; */ + const onCancel = () => { if (form.type === 'subscription') { setState((state) => ({ @@ -111,8 +153,63 @@ const SettingsReplicationForm = ({ pglogicalReplicationFormId }) => { onCancel={onCancel} canReset buttonsLabels={{ submitLabel }} + clearOnUnmount={form.type !== 'replication'} /> ); + + /* if (form.type === 'subscription') { + + } else { + return !isLoading && ( +
+
+
+ +
+ +
+ onCellClick(selectedRow, cellType, formOptions)} + /> +
+
+
+ + + +
+
+ ); + } */ }; SettingsReplicationForm.propTypes = { diff --git a/app/javascript/components/settings-replication-form/settings-replication-form.schema.js b/app/javascript/components/settings-replication-form/settings-replication-form.schema.js index 8c5491a0963..e2cc5deacac 100644 --- a/app/javascript/components/settings-replication-form/settings-replication-form.schema.js +++ b/app/javascript/components/settings-replication-form/settings-replication-form.schema.js @@ -1,42 +1,8 @@ /* eslint-disable camelcase */ import { componentTypes, validatorTypes } from '@@ddf'; +import { createRows } from './helper'; const createSchema = (initialValues, subscriptions, form, replicationHelperText, setState) => { - // Creates the rows for the 'subscriptions-table' component - const createRows = () => { - const rows = []; - - subscriptions.forEach((value, index) => { - rows.push({ - id: index.toString(), - dbname: { text: value.dbname }, - host: { text: value.host }, - user: { text: value.user }, - password: { text: value.password }, - port: { text: value.port }, - backlog: { text: value.backlog ? value.backlog : '' }, - status: { text: value.status ? value.status : '' }, - provider_region: { text: value.provider_region || value.provider_region === 0 ? value.provider_region : '' }, - edit: { - is_button: true, - text: __('Update'), - kind: 'tertiary', - size: 'md', - callback: 'editSubscription', - }, - delete: { - is_button: true, - text: __('Delete'), - kind: 'danger', - size: 'md', - callback: 'deleteSubscription', - }, - }); - }); - - return rows; - }; - const deleteSubscription = (selectedRow, cellType, formOptions) => { subscriptions.splice(selectedRow.id, 1); @@ -44,6 +10,11 @@ const createSchema = (initialValues, subscriptions, form, replicationHelperText, ...state, subscriptions, })); + + console.log(formOptions.getFieldState('subscriptions-table')); + console.log(formOptions.getRegisteredFields()); + console.log(formOptions.getState()); + console.log(formOptions.schema); }; const editSubscription = (selectedRow) => { @@ -56,6 +27,7 @@ const createSchema = (initialValues, subscriptions, form, replicationHelperText, user: selectedRow.cells[2].value, password: selectedRow.cells[3].value, port: selectedRow.cells[4].value, + subId: selectedRow.id, }, form: { type: 'subscription', @@ -118,7 +90,7 @@ const createSchema = (initialValues, subscriptions, form, replicationHelperText, component: 'subscriptions-table', name: 'subscriptions-table', id: 'subscriptions-table', - rows: createRows(), + rows: createRows(subscriptions), onCellClick: (selectedRow, cellType, formOptions) => { switch (selectedRow.callbackAction) { case 'editSubscription': @@ -133,11 +105,10 @@ const createSchema = (initialValues, subscriptions, form, replicationHelperText, }, addButtonLabel: __('Add Subscription'), onButtonClick: (formOptions) => { - formOptions.change('dbname', ''); - formOptions.change('host', ''); - formOptions.change('user', ''); - formOptions.change('password', ''); - formOptions.change('port', ''); + console.log(formOptions.getRegisteredFields()); + console.log(formOptions.getState()); + console.log(formOptions.schema); + setState((state) => ({ ...state, initialValues: { @@ -150,6 +121,10 @@ const createSchema = (initialValues, subscriptions, form, replicationHelperText, action: 'add', }, })); + + console.log(formOptions.getRegisteredFields()); + console.log(formOptions.getState()); + console.log(formOptions.schema); }, }], }, diff --git a/app/javascript/components/settings-replication-form/subscriptions-table.jsx b/app/javascript/components/settings-replication-form/subscriptions-table.jsx new file mode 100644 index 00000000000..17d8bff9cd8 --- /dev/null +++ b/app/javascript/components/settings-replication-form/subscriptions-table.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { useFieldApi, useFormApi } from '@@ddf'; +import { Button } from 'carbon-components-react'; +import MiqDataTable from '../miq-data-table'; + +export const SubscriptionsTableComponent = (props) => { + const { + rows, onCellClick, addButtonLabel, onButtonClick, + } = useFieldApi(props); + const formOptions = useFormApi(); + + return ( +
+
+ +
+ +
+ onCellClick(selectedRow, cellType, formOptions)} + /> +
+
+ ); +};