import Immutable from 'seamless-immutable'; import { translate as __ } from 'foremanReact/common/I18n'; import { calculateServiceUsage } from './ApplicationInstanceHelper'; import { cloneDeep, findIndex, findLastIndex, } from 'lodash'; import { APPLICATION_INSTANCE_INIT, APPLICATION_INSTANCE_CLOSE_ALERT_MODAL, APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_FAILURE, APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_REQUEST, APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_SUCCESS, APPLICATION_INSTANCE_HOST_DELETE, APPLICATION_INSTANCE_HOST_ADD, APPLICATION_INSTANCE_HOST_EDIT_ACTIVATE, APPLICATION_INSTANCE_HOST_EDIT_CONFIRM, APPLICATION_INSTANCE_HOST_EDIT_CHANGE, APPLICATION_INSTANCE_HOST_EDIT_CANCEL, APPLICATION_INSTANCE_HOST_EDIT_ERROR, APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_OPEN, APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_CLOSE, APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_OPEN, APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_CLOSE, APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN, APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE, APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE, } from './ApplicationInstanceConstants'; import { PARAMETER_SELECTION_PARAM_TYPE_FOREMAN, PARAMETER_SELECTION_PARAM_TYPE_ANSIBLE, } from '../ParameterSelection/ParameterSelectionConstants'; export const initialState = Immutable({ name: false, error: { errorMsg: '', status: '', statusText: '' }, }); const applicationInstanceConf = (state = initialState, action) => { const { payload } = action; switch (action.type) { case APPLICATION_INSTANCE_INIT: { return state.merge(payload); } case APPLICATION_INSTANCE_CLOSE_ALERT_MODAL: { return state.merge({ showAlertModal: false, alertModalTitle: '', alertModalText: '', }); } case APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_FAILURE: { console.log("Error while loading application definition data: "+ payload.error); return state.merge({ error: payload.error, loading: false }); } case APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_REQUEST: { return state.set('loading', true); } case APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_SUCCESS: { let newState = {}; const services = JSON.parse(payload.app_definition.services); // initialize all services count with 0 services.map(serv => { serv['currentCount'] = 0; }) // Update count if (state.hosts !== undefined) { state.hosts.map((host, index) => { const hostServiceId = Number(host.service); const service = services.find(serv => serv['id'] == hostServiceId); service['currentCount'] += 1; }); } newState = { appDefinition: payload.app_definition, services: services, loading: false, }; // Initialize ansibleVarsAll if there is no data available in app instance if (state.ansibleVarsAll.length <= 0) { newState['ansibleVarsAll'] = JSON.parse(payload.app_definition.ansible_vars_all); } return state.merge(newState); } case APPLICATION_INSTANCE_HOST_ADD: { let hosts = []; let index = 1; if ('hosts' in state && state.hosts !== undefined && state.hosts.length > 0) { hosts = cloneDeep(state.hosts); index = Math.max(...hosts.map(e => e.id)) + 1; } const newRow = {id: index, hostname: "", description: '', service: '', isExistingHost: false, foremanParameters: [], ansibleParameters: [], newEntry: true }; newRow.backup = cloneDeep(newRow) hosts.push(newRow); return state.merge({ editMode: true, hosts: hosts }); } case APPLICATION_INSTANCE_HOST_DELETE: { const services = cloneDeep(state.services); const host = state.hosts.find(v => v.id == payload.rowData.id); const hostServiceId = Number(host.service); const hosts = state.hosts.filter(v => v.id !== host.id); // Update count const service = services.find(serv => serv['id'] == hostServiceId); service['currentCount'] -= 1; return state.merge({ hosts: hosts, services: services, }) } case APPLICATION_INSTANCE_HOST_EDIT_ACTIVATE: { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: payload.rowData.id }); hosts[index].backup = cloneDeep(hosts[index]); return state.merge({ editMode: true, hosts: hosts }); } case APPLICATION_INSTANCE_HOST_EDIT_CONFIRM: { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: payload.rowData.id }); let services = cloneDeep(state.services); const thisHost = hosts[index]; // hostnames are lower case thisHost.hostname = thisHost.hostname.toLowerCase(); if (state.hosts.filter(v => v.hostname === thisHost.hostname && v.id != thisHost.id).length > 0) { return state.merge({ showAlertModal: true, alertModalTitle: __("Error"), alertModalText: __("Host name already used in this Application Instance. Please make sure that every host name is unique."), }); } // Initialize the new Instance with the parameters of the Application Definition. if (thisHost.newEntry === true) { const hostServiceId = Number(thisHost.service); const selectedService = services.filter(entry => entry.id == hostServiceId)[0]; hosts[index].foremanParameters = selectedService.foremanParameters; hosts[index].ansibleParameters = selectedService.ansibleParameters; services = calculateServiceUsage(hostServiceId, services); } delete hosts[index].backup; delete hosts[index].newEntry; return state.merge({ editMode: false, services: services, hosts: hosts }); } case APPLICATION_INSTANCE_HOST_EDIT_CHANGE: { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: payload.rowData.id }); hosts[index][payload.property] = payload.value; return state.set('hosts', hosts); } case APPLICATION_INSTANCE_HOST_EDIT_CANCEL: { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: payload.rowData.id }); hosts[index] = cloneDeep(hosts[index].backup); delete hosts[index].backup; if (hosts[index].newEntry === true) { hosts.splice(index, 1); } return state.merge({ editMode: false, hosts: hosts }); } case APPLICATION_INSTANCE_HOST_EDIT_ERROR: { return state.merge({ showAlertModal: true, alertModalTitle: __("Error"), alertModalText: payload, }); } case APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_OPEN: { let parametersData = {}; const selectedService = state.services.filter(entry => entry.id == payload.rowData.service)[0]; parametersData.paramDefinition = { id: selectedService.id, name: selectedService.name, dataId: selectedService.hostgroup, hostId: payload.rowData.id, // TODO: is this really correct? Guess it shoud be dataId and we should get rid of them //hostgroup_id: selectedService.hostgroup, }; parametersData.type = PARAMETER_SELECTION_PARAM_TYPE_FOREMAN; parametersData.parameters = payload.rowData.foremanParameters; parametersData.useDefaultValue = false; parametersData.allowRowAdjustment = false; parametersData.allowNameAdjustment = false; parametersData.allowDescriptionAdjustment = false; return state.merge({ parametersData: parametersData, }); } case APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_CLOSE: { if (payload.mode == 'save') { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: state.parametersData.paramDefinition.hostId }); hosts[index].foremanParameters = cloneDeep(payload.parameterSelection); return state.merge({ parametersData: null, hosts: hosts }); } else { return state.merge({ parametersData: null, }); } } case APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_OPEN: { let parametersData = {}; if ((payload.hasOwnProperty('isAllGroup')) && (payload.isAllGroup == true)) { parametersData.parameters = state.ansibleVarsAll; parametersData.paramDefinition = { isAllGroup: true, } } else { const selectedService = state.services.filter(entry => entry.id == payload.rowData.service)[0]; parametersData.paramDefinition = { id: selectedService.id, name: selectedService.name, hostId: payload.rowData.id, // TODO: is this really correct? Guess it shoud be dataId and we should get rid of them //hostgroup_id: selectedService.hostgroup, }; parametersData.parameters = payload.rowData.ansibleParameters; } parametersData.type = PARAMETER_SELECTION_PARAM_TYPE_ANSIBLE; parametersData.useDefaultValue = false; parametersData.allowRowAdjustment = false; parametersData.allowNameAdjustment = false; parametersData.allowDescriptionAdjustment = false; return state.merge({ parametersData: parametersData, }); } case APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_CLOSE: { let newState = {}; if (payload.mode == 'save') { if ((state.parametersData.paramDefinition.hasOwnProperty('isAllGroup')) && (state.parametersData.paramDefinition.isAllGroup == true)) { newState = { parametersData: null, ansibleVarsAll: cloneDeep(payload.parameterSelection), }; } else { const hosts = cloneDeep(state.hosts); const index = findIndex(hosts, { id: state.parametersData.paramDefinition.hostId }); hosts[index].ansibleParameters = cloneDeep(payload.parameterSelection); newState = { parametersData: null, hosts: hosts }; } } else { newState = { parametersData: null, }; } return state.merge(newState); } case APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN: { } case APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE: { if (payload.mode == 'save') { let newState; let hosts = []; let index = 1; let services = cloneDeep(state.services); if ('hosts' in state && state.hosts !== undefined && state.hosts.length > 0) { hosts = cloneDeep(state.hosts); index = Math.max(...hosts.map(e => e.id)); } payload.selectedHosts.forEach(host => { if ((state.hosts == undefined) || (state.hosts.find(h => h.hostname == host.hostname) == undefined)) { index += 1; const selectedService = services.filter(entry => entry.id == host.serviceId)[0]; const newRow = { id: index, hostname: host.hostname, description: '', service: host.serviceId, isExistingHost: true, foremanParameters: [], // we will never set this because we don't want to change a already existing host. ansibleParameters: selectedService.ansibleParameters, } hosts.push(newRow); services = calculateServiceUsage(host.serviceId, services); } }); return state.merge({ hosts: hosts, services, services }); } else { return state; } } case APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE: { return state.merge({ paramEditMode: payload.mode }); } default: return state; } }; export default applicationInstanceConf;