Run undeploy_plan workflow to delete deployment
* create separate UndeployProgress components to track deletion of deployment * unify deploy/undeploy transition when issuing the workflow using UI state rather than custom UI deployment state (STARTING_DEPLOYMENT) Depends-On: Ibd1da1aee8415712b9a418c6738f6ea9a2828a55 Implements: blueprint config-download-ui Change-Id: Idec2534a583f6bea7c74bbdb8a08b9a81b7aa3f8
This commit is contained in:
parent
3691bab67d
commit
e81f96469b
10
releasenotes/notes/config-download-0600de77081b1094.yaml
Normal file
10
releasenotes/notes/config-download-0600de77081b1094.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added integration of config-download deployment as a default deployment way
|
||||||
|
using TripleO-UI. Config Download feature splits deployment into 2 parts, at
|
||||||
|
first, Heat creates all the deployment data necessary via SoftwareDeployment
|
||||||
|
resources to perform the Overcloud installation and configuration. In second
|
||||||
|
part, using downloaded data from Heat, Ansible playbooks and tasks are
|
||||||
|
generated and are then used by the Undercloud to complete the configuration
|
||||||
|
of the Overcloud.
|
@ -25,7 +25,12 @@ import {
|
|||||||
START_DEPLOYMENT_PENDING,
|
START_DEPLOYMENT_PENDING,
|
||||||
START_DEPLOYMENT_SUCCESS,
|
START_DEPLOYMENT_SUCCESS,
|
||||||
DEPLOYMENT_FAILED,
|
DEPLOYMENT_FAILED,
|
||||||
DEPLOYMENT_SUCCESS
|
DEPLOYMENT_SUCCESS,
|
||||||
|
START_UNDEPLOY_FAILED,
|
||||||
|
START_UNDEPLOY_PENDING,
|
||||||
|
START_UNDEPLOY_SUCCESS,
|
||||||
|
UNDEPLOY_FAILED,
|
||||||
|
UNDEPLOY_SUCCESS
|
||||||
} from '../constants/DeploymentConstants';
|
} from '../constants/DeploymentConstants';
|
||||||
import { handleErrors } from './ErrorActions';
|
import { handleErrors } from './ErrorActions';
|
||||||
import MistralConstants from '../constants/MistralConstants';
|
import MistralConstants from '../constants/MistralConstants';
|
||||||
@ -91,9 +96,9 @@ export const startDeploymentSuccess = planName => ({
|
|||||||
payload: planName
|
payload: planName
|
||||||
});
|
});
|
||||||
|
|
||||||
export const startDeploymentFailed = (planName, message) => ({
|
export const startDeploymentFailed = planName => ({
|
||||||
type: START_DEPLOYMENT_FAILED,
|
type: START_DEPLOYMENT_FAILED,
|
||||||
payload: { planName, message }
|
payload: planName
|
||||||
});
|
});
|
||||||
|
|
||||||
export const startDeployment = planName => dispatch => {
|
export const startDeployment = planName => dispatch => {
|
||||||
@ -143,3 +148,67 @@ export const deploymentFinished = execution => (
|
|||||||
dispatch(deploymentSuccess(planName, message));
|
dispatch(deploymentSuccess(planName, message));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const startUndeployPending = planName => ({
|
||||||
|
type: START_UNDEPLOY_PENDING,
|
||||||
|
payload: planName
|
||||||
|
});
|
||||||
|
|
||||||
|
export const startUndeploySuccess = planName => ({
|
||||||
|
type: START_UNDEPLOY_SUCCESS,
|
||||||
|
payload: planName
|
||||||
|
});
|
||||||
|
|
||||||
|
export const startUndeployFailed = planName => ({
|
||||||
|
type: START_UNDEPLOY_FAILED,
|
||||||
|
payload: planName
|
||||||
|
});
|
||||||
|
|
||||||
|
export const startUndeploy = planName => dispatch => {
|
||||||
|
dispatch(startUndeployPending(planName));
|
||||||
|
dispatch(
|
||||||
|
startWorkflow(
|
||||||
|
MistralConstants.UNDEPLOY_PLAN,
|
||||||
|
{
|
||||||
|
container: planName,
|
||||||
|
timeout: 240
|
||||||
|
},
|
||||||
|
execution => dispatch(undeployFinished(execution)),
|
||||||
|
10 * 60 * 1000
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(execution => dispatch(startUndeploySuccess(planName)))
|
||||||
|
.catch(error => {
|
||||||
|
dispatch(
|
||||||
|
handleErrors(error, `Plan ${planName} deployment could not be deleted`)
|
||||||
|
);
|
||||||
|
dispatch(startUndeployFailed(planName));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const undeploySuccess = (planName, message) => ({
|
||||||
|
type: UNDEPLOY_SUCCESS,
|
||||||
|
payload: { planName, message }
|
||||||
|
});
|
||||||
|
|
||||||
|
export const undeployFailed = (planName, message) => ({
|
||||||
|
type: UNDEPLOY_FAILED,
|
||||||
|
payload: { planName, message }
|
||||||
|
});
|
||||||
|
|
||||||
|
export const undeployFinished = execution => (
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
{ getIntl }
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
input: { container: planName },
|
||||||
|
output: { message },
|
||||||
|
state
|
||||||
|
} = execution;
|
||||||
|
if (state === 'ERROR') {
|
||||||
|
dispatch(undeployFailed(planName, message));
|
||||||
|
} else {
|
||||||
|
dispatch(undeploySuccess(planName, message));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -174,41 +174,5 @@ export default {
|
|||||||
dispatch(this.fetchEnvironmentFailed(stack));
|
dispatch(this.fetchEnvironmentFailed(stack));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
|
||||||
|
|
||||||
deleteStackSuccess(stackName) {
|
|
||||||
return {
|
|
||||||
type: StacksConstants.DELETE_STACK_SUCCESS,
|
|
||||||
payload: stackName
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteStackFailed() {
|
|
||||||
return {
|
|
||||||
type: StacksConstants.DELETE_STACK_FAILED
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteStackPending() {
|
|
||||||
return {
|
|
||||||
type: StacksConstants.DELETE_STACK_PENDING
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a delete request for a stack.
|
|
||||||
*/
|
|
||||||
deleteStack(stack) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch(this.deleteStackPending());
|
|
||||||
dispatch(HeatApiService.deleteStack(stack.stack_name, stack.id))
|
|
||||||
.then(response => {
|
|
||||||
dispatch(this.deleteStackSuccess(stack.stack_name));
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
dispatch(handleErrors(error, 'Stack could not be deleted'));
|
|
||||||
dispatch(this.deleteStackFailed());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -14,20 +14,25 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { deploymentStates } from '../constants/DeploymentConstants';
|
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
import { normalize } from 'normalizr';
|
||||||
|
|
||||||
|
import { deploymentStates } from '../constants/DeploymentConstants';
|
||||||
|
import { getCurrentStack } from '../selectors/stacks';
|
||||||
import LoggerActions from './LoggerActions';
|
import LoggerActions from './LoggerActions';
|
||||||
import NodesActions from './NodesActions';
|
import NodesActions from './NodesActions';
|
||||||
import PlansActions from './PlansActions';
|
import PlansActions from './PlansActions';
|
||||||
import RegisterNodesActions from './RegisterNodesActions';
|
import RegisterNodesActions from './RegisterNodesActions';
|
||||||
import RolesActions from './RolesActions';
|
import RolesActions from './RolesActions';
|
||||||
import StacksActions from './StacksActions';
|
import StacksActions from './StacksActions';
|
||||||
|
import { stackSchema } from '../normalizrSchemas/stacks';
|
||||||
import MistralConstants from '../constants/MistralConstants';
|
import MistralConstants from '../constants/MistralConstants';
|
||||||
import ZaqarWebSocketService from '../services/ZaqarWebSocketService';
|
import ZaqarWebSocketService from '../services/ZaqarWebSocketService';
|
||||||
import { handleWorkflowMessage } from './WorkflowActions';
|
import { handleWorkflowMessage } from './WorkflowActions';
|
||||||
import {
|
import {
|
||||||
getDeploymentStatusSuccess,
|
getDeploymentStatusSuccess,
|
||||||
deploymentFinished,
|
deploymentFinished,
|
||||||
|
undeployFinished,
|
||||||
configDownloadMessage
|
configDownloadMessage
|
||||||
} from './DeploymentActions';
|
} from './DeploymentActions';
|
||||||
import NetworksActions from './NetworksActions';
|
import NetworksActions from './NetworksActions';
|
||||||
@ -142,12 +147,19 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MistralConstants.HEAT_STACKS_GET: {
|
case MistralConstants.HEAT_STACKS_LIST: {
|
||||||
const { stack, stack: { stack_name, id } } = payload;
|
const stacks =
|
||||||
dispatch(StacksActions.fetchStackSuccess(stack));
|
normalize(payload.stacks, [stackSchema]).entities.stacks || {};
|
||||||
!getState().stacks.isFetchingResources &&
|
dispatch(StacksActions.fetchStacksSuccess(stacks));
|
||||||
|
|
||||||
|
// TODO(jtomasek): It would be nicer if we could identify that
|
||||||
|
// stack has changed in the component and fetch resources there
|
||||||
|
const { isFetchingResources } = getState().stacks;
|
||||||
|
const currentStack = getCurrentStack(getState());
|
||||||
|
if (!isFetchingResources && currentStack) {
|
||||||
|
const { stack_name, id } = currentStack;
|
||||||
dispatch(StacksActions.fetchResources(stack_name, id));
|
dispatch(StacksActions.fetchResources(stack_name, id));
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case MistralConstants.CONFIG_DOWNLOAD_DEPLOY: {
|
case MistralConstants.CONFIG_DOWNLOAD_DEPLOY: {
|
||||||
@ -170,6 +182,25 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MistralConstants.UNDEPLOY_PLAN: {
|
||||||
|
if (payload.deployment_status === deploymentStates.UNDEPLOYING) {
|
||||||
|
const { message, plan_name, deployment_status } = payload;
|
||||||
|
dispatch(
|
||||||
|
getDeploymentStatusSuccess(plan_name, {
|
||||||
|
status: deployment_status,
|
||||||
|
message
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dispatch(
|
||||||
|
handleWorkflowMessage(payload.execution_id, execution =>
|
||||||
|
dispatch(undeployFinished(execution))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MistralConstants.PLAN_EXPORT: {
|
case MistralConstants.PLAN_EXPORT: {
|
||||||
dispatch(
|
dispatch(
|
||||||
handleWorkflowMessage(payload.execution.id, execution =>
|
handleWorkflowMessage(payload.execution.id, execution =>
|
||||||
|
@ -27,7 +27,6 @@ import {
|
|||||||
CloseModalXButton,
|
CloseModalXButton,
|
||||||
RoutedModalPanel
|
RoutedModalPanel
|
||||||
} from '../ui/Modals';
|
} from '../ui/Modals';
|
||||||
import { deploymentStates } from '../../constants/DeploymentConstants';
|
|
||||||
import { getCurrentPlanName } from '../../selectors/plans';
|
import { getCurrentPlanName } from '../../selectors/plans';
|
||||||
import {
|
import {
|
||||||
getCurrentPlanDeploymentStatus,
|
getCurrentPlanDeploymentStatus,
|
||||||
@ -91,14 +90,11 @@ class DeploymentConfirmation extends React.Component {
|
|||||||
const {
|
const {
|
||||||
allValidationsSuccessful,
|
allValidationsSuccessful,
|
||||||
currentPlanName,
|
currentPlanName,
|
||||||
deploymentStatus,
|
|
||||||
startDeployment,
|
startDeployment,
|
||||||
environmentSummary
|
environmentSummary,
|
||||||
|
isPendingDeploymentRequest
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const buttonDisabled =
|
|
||||||
deploymentStatus.status === deploymentStates.STARTING_DEPLOYMENT;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoutedModalPanel redirectPath={`/plans/${currentPlanName}`}>
|
<RoutedModalPanel redirectPath={`/plans/${currentPlanName}`}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
@ -132,7 +128,7 @@ class DeploymentConfirmation extends React.Component {
|
|||||||
<FormattedMessage {...messages.deploymentConfirmation} />
|
<FormattedMessage {...messages.deploymentConfirmation} />
|
||||||
</p>
|
</p>
|
||||||
<DeployButton
|
<DeployButton
|
||||||
disabled={buttonDisabled}
|
disabled={isPendingDeploymentRequest}
|
||||||
deploy={startDeployment.bind(this, currentPlanName)}
|
deploy={startDeployment.bind(this, currentPlanName)}
|
||||||
/>
|
/>
|
||||||
</BlankSlate>
|
</BlankSlate>
|
||||||
@ -153,6 +149,7 @@ DeploymentConfirmation.propTypes = {
|
|||||||
deploymentStatus: PropTypes.object.isRequired,
|
deploymentStatus: PropTypes.object.isRequired,
|
||||||
environmentSummary: PropTypes.string.isRequired,
|
environmentSummary: PropTypes.string.isRequired,
|
||||||
intl: PropTypes.object,
|
intl: PropTypes.object,
|
||||||
|
isPendingDeploymentRequest: PropTypes.bool.isRequired,
|
||||||
runPreDeploymentValidations: PropTypes.func.isRequired,
|
runPreDeploymentValidations: PropTypes.func.isRequired,
|
||||||
startDeployment: PropTypes.func.isRequired
|
startDeployment: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
@ -163,7 +160,9 @@ const mapStateToProps = (state, props) => ({
|
|||||||
deploymentStatusLoaded: getCurrentPlanDeploymentStatusUI(state).isLoaded,
|
deploymentStatusLoaded: getCurrentPlanDeploymentStatusUI(state).isLoaded,
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
deploymentStatusUIError: getCurrentPlanDeploymentStatusUI(state).error,
|
deploymentStatusUIError: getCurrentPlanDeploymentStatusUI(state).error,
|
||||||
environmentSummary: getEnvironmentConfigurationSummary(state)
|
environmentSummary: getEnvironmentConfigurationSummary(state),
|
||||||
|
isPendingDeploymentRequest: getCurrentPlanDeploymentStatusUI(state)
|
||||||
|
.isPendingRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
@ -21,6 +21,7 @@ import PropTypes from 'prop-types';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DeploymentProgress from './DeploymentProgress';
|
import DeploymentProgress from './DeploymentProgress';
|
||||||
|
import UndeployProgress from './UndeployProgress';
|
||||||
import DeploymentFailure from './DeploymentFailure';
|
import DeploymentFailure from './DeploymentFailure';
|
||||||
import { deploymentStates } from '../../constants/DeploymentConstants';
|
import { deploymentStates } from '../../constants/DeploymentConstants';
|
||||||
import { getCurrentPlanName } from '../../selectors/plans';
|
import { getCurrentPlanName } from '../../selectors/plans';
|
||||||
@ -56,21 +57,12 @@ class DeploymentDetail extends React.Component {
|
|||||||
|
|
||||||
switch (deploymentStatus.status) {
|
switch (deploymentStatus.status) {
|
||||||
case deploymentStates.DEPLOYING:
|
case deploymentStates.DEPLOYING:
|
||||||
case deploymentStates.UNDEPLOYING:
|
|
||||||
return <DeploymentProgress planName={currentPlanName} />;
|
return <DeploymentProgress planName={currentPlanName} />;
|
||||||
case deploymentStates.DEPLOY_SUCCESS:
|
case deploymentStates.UNDEPLOYING:
|
||||||
return (
|
return <UndeployProgress planName={currentPlanName} />;
|
||||||
<div>
|
case deploymentStates.UNDEPLOY_FAILED:
|
||||||
{deploymentStatus.status}
|
|
||||||
{deploymentStatus.message}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case deploymentStates.DEPLOY_FAILED:
|
case deploymentStates.DEPLOY_FAILED:
|
||||||
return <DeploymentFailure planName={currentPlanName} />;
|
return <DeploymentFailure planName={currentPlanName} />;
|
||||||
case deploymentStates.UNDEPLOY_FAILED:
|
|
||||||
// TODO(jtomasek): handle undeploy failure
|
|
||||||
return 'undeploy failed';
|
|
||||||
case deploymentStates.UNKNOWN:
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,14 @@ import React from 'react';
|
|||||||
import DeleteStackButton from '../deployment_plan/DeleteStackButton';
|
import DeleteStackButton from '../deployment_plan/DeleteStackButton';
|
||||||
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
|
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
|
||||||
import { getCurrentStack } from '../../selectors/stacks';
|
import { getCurrentStack } from '../../selectors/stacks';
|
||||||
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
import {
|
||||||
|
getCurrentPlanDeploymentStatus,
|
||||||
|
getCurrentPlanDeploymentStatusUI
|
||||||
|
} from '../../selectors/deployment';
|
||||||
import InlineNotification from '../ui/InlineNotification';
|
import InlineNotification from '../ui/InlineNotification';
|
||||||
import { sanitizeMessage } from '../../utils';
|
import { sanitizeMessage } from '../../utils';
|
||||||
import StacksActions from '../../actions/StacksActions';
|
import StacksActions from '../../actions/StacksActions';
|
||||||
|
import { startUndeploy } from '../../actions/DeploymentActions';
|
||||||
|
|
||||||
class DeploymentFailure extends React.Component {
|
class DeploymentFailure extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -38,9 +42,9 @@ class DeploymentFailure extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
deploymentStatus: { status, message },
|
deploymentStatus: { status, message },
|
||||||
deleteStack,
|
undeployPlan,
|
||||||
intl: { formatMessage },
|
intl: { formatMessage },
|
||||||
isRequestingStackDelete,
|
isPendingRequest,
|
||||||
planName,
|
planName,
|
||||||
stack
|
stack
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -53,36 +57,37 @@ class DeploymentFailure extends React.Component {
|
|||||||
>
|
>
|
||||||
<p>{sanitizeMessage(message)}</p>
|
<p>{sanitizeMessage(message)}</p>
|
||||||
</InlineNotification>
|
</InlineNotification>
|
||||||
|
{stack && (
|
||||||
<DeleteStackButton
|
<DeleteStackButton
|
||||||
deleteStack={deleteStack.bind(this, stack)}
|
deleteStack={undeployPlan.bind(this, planName)}
|
||||||
disabled={isRequestingStackDelete || !stack}
|
disabled={isPendingRequest}
|
||||||
loaded={!isRequestingStackDelete}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeploymentFailure.propTypes = {
|
DeploymentFailure.propTypes = {
|
||||||
deleteStack: PropTypes.func.isRequired,
|
|
||||||
deploymentStatus: PropTypes.object.isRequired,
|
deploymentStatus: PropTypes.object.isRequired,
|
||||||
fetchStacks: PropTypes.func.isRequired,
|
fetchStacks: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object,
|
intl: PropTypes.object,
|
||||||
isFetchingStacks: PropTypes.bool.isRequired,
|
isFetchingStacks: PropTypes.bool.isRequired,
|
||||||
isRequestingStackDelete: PropTypes.bool.isRequired,
|
isPendingRequest: PropTypes.bool.isRequired,
|
||||||
planName: PropTypes.string.isRequired,
|
planName: PropTypes.string.isRequired,
|
||||||
stack: ImmutablePropTypes.record
|
stack: ImmutablePropTypes.record,
|
||||||
|
undeployPlan: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
isFetchingStacks: state.stacks.isFetching,
|
isFetchingStacks: state.stacks.isFetching,
|
||||||
isRequestingStackDelete: state.stacks.isRequestingStackDelete,
|
isPendingRequest: getCurrentPlanDeploymentStatusUI(state).isPendingRequest,
|
||||||
stack: getCurrentStack(state)
|
stack: getCurrentStack(state)
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
deleteStack: stack => dispatch(StacksActions.deleteStack(stack)),
|
undeployPlan: planName => dispatch(startUndeploy(planName)),
|
||||||
fetchStacks: () => dispatch(StacksActions.fetchStacks())
|
fetchStacks: () => dispatch(StacksActions.fetchStacks())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import {
|
|||||||
getCreateCompleteResources
|
getCreateCompleteResources
|
||||||
} from '../../selectors/stacks';
|
} from '../../selectors/stacks';
|
||||||
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
||||||
import { InlineLoader } from '../ui/Loader';
|
import { InlineLoader, Loader } from '../ui/Loader';
|
||||||
import StackResourcesTable from './StackResourcesTable';
|
import StackResourcesTable from './StackResourcesTable';
|
||||||
import { stackStates } from '../../constants/StacksConstants';
|
import { stackStates } from '../../constants/StacksConstants';
|
||||||
|
|
||||||
@ -37,14 +37,6 @@ const messages = defineMessages({
|
|||||||
id: 'DeploymentSuccess.resources',
|
id: 'DeploymentSuccess.resources',
|
||||||
defaultMessage: 'Resources'
|
defaultMessage: 'Resources'
|
||||||
},
|
},
|
||||||
cancelDeployment: {
|
|
||||||
id: 'DeploymentProgress.cancelDeployment',
|
|
||||||
defaultMessage: 'Cancel Deployment'
|
|
||||||
},
|
|
||||||
requestingDeletion: {
|
|
||||||
id: 'DeploymentProgress.requestingDeletion',
|
|
||||||
defaultMessage: 'Requesting Deletion of Deployment'
|
|
||||||
},
|
|
||||||
initializingDeployment: {
|
initializingDeployment: {
|
||||||
id: 'DeploymentProgress.initializingDeployment',
|
id: 'DeploymentProgress.initializingDeployment',
|
||||||
defaultMessage: 'Initializing {planName} plan deployment'
|
defaultMessage: 'Initializing {planName} plan deployment'
|
||||||
@ -70,11 +62,16 @@ class DeploymentProgress extends React.Component {
|
|||||||
resources,
|
resources,
|
||||||
resourcesLoaded,
|
resourcesLoaded,
|
||||||
stackDeploymentProgress,
|
stackDeploymentProgress,
|
||||||
stack
|
stack,
|
||||||
|
stacksLoaded
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalBody className="flex-container">
|
<ModalBody className="flex-container">
|
||||||
|
<Loader
|
||||||
|
loaded={stacksLoaded}
|
||||||
|
componentProps={{ className: 'flex-container' }}
|
||||||
|
>
|
||||||
{!stack && (
|
{!stack && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="progress-description">
|
<div className="progress-description">
|
||||||
@ -141,6 +138,7 @@ class DeploymentProgress extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
</Loader>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -158,22 +156,23 @@ DeploymentProgress.propTypes = {
|
|||||||
resourcesCount: PropTypes.number,
|
resourcesCount: PropTypes.number,
|
||||||
resourcesLoaded: PropTypes.bool.isRequired,
|
resourcesLoaded: PropTypes.bool.isRequired,
|
||||||
stack: ImmutablePropTypes.record,
|
stack: ImmutablePropTypes.record,
|
||||||
stackDeploymentProgress: PropTypes.number.isRequired
|
stackDeploymentProgress: PropTypes.number.isRequired,
|
||||||
|
stacksLoaded: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
completeResourcesCount: getCreateCompleteResources(state).size,
|
completeResourcesCount: getCreateCompleteResources(state).size,
|
||||||
stack: getCurrentStack(state),
|
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
isFetchingStacks: state.stacks.isFetching,
|
isFetchingStacks: state.stacks.isFetching,
|
||||||
stackDeploymentProgress: getCurrentStackDeploymentProgress(state),
|
|
||||||
resourcesCount: state.stacks.resources.size,
|
resourcesCount: state.stacks.resources.size,
|
||||||
resources: state.stacks.resources,
|
resources: state.stacks.resources,
|
||||||
resourcesLoaded: state.stacks.resourcesLoaded
|
resourcesLoaded: state.stacks.resourcesLoaded,
|
||||||
|
stack: getCurrentStack(state),
|
||||||
|
stackDeploymentProgress: getCurrentStackDeploymentProgress(state),
|
||||||
|
stacksLoaded: state.stacks.isLoaded
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { planName }) => ({
|
const mapDispatchToProps = (dispatch, { planName }) => ({
|
||||||
deleteStack: () => dispatch(StacksActions.deleteStack(planName, '')),
|
|
||||||
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
||||||
fetchResources: (stackName, stackId) =>
|
fetchResources: (stackName, stackId) =>
|
||||||
dispatch(StacksActions.fetchResources(stackName, stackId))
|
dispatch(StacksActions.fetchResources(stackName, stackId))
|
||||||
|
167
src/js/components/deployment/UndeployProgress.js
Normal file
167
src/js/components/deployment/UndeployProgress.js
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { ModalBody, ProgressBar } from 'react-bootstrap';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getCurrentStack,
|
||||||
|
getCurrentStackDeletionProgress
|
||||||
|
} from '../../selectors/stacks';
|
||||||
|
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
||||||
|
import { InlineLoader, Loader } from '../ui/Loader';
|
||||||
|
import StackResourcesTable from './StackResourcesTable';
|
||||||
|
import { stackStates } from '../../constants/StacksConstants';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
resources: {
|
||||||
|
id: 'UndeployProgress.resources',
|
||||||
|
defaultMessage: 'Resources'
|
||||||
|
},
|
||||||
|
initializingUndeploy: {
|
||||||
|
id: 'UndeployProgress.initializingDeployment',
|
||||||
|
defaultMessage: 'Initializing {planName} plan deployment deletion'
|
||||||
|
},
|
||||||
|
undeployingPlan: {
|
||||||
|
id: 'UndeployProgress.undeployingPlan',
|
||||||
|
defaultMessage: 'Deleting {planName} plan deployment'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class UndeployProgress extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
deploymentStatus: { message },
|
||||||
|
planName,
|
||||||
|
resources,
|
||||||
|
resourcesLoaded,
|
||||||
|
stackDeletionProgress,
|
||||||
|
stack,
|
||||||
|
stacksLoaded
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalBody className="flex-container">
|
||||||
|
<Loader
|
||||||
|
loaded={stacksLoaded}
|
||||||
|
componentProps={{ className: 'flex-container' }}
|
||||||
|
>
|
||||||
|
{stack &&
|
||||||
|
stack.stack_status !== stackStates.DELETE_IN_PROGRESS && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.initializingUndeploy}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
now={0}
|
||||||
|
label={<span>0%</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
{stack &&
|
||||||
|
stack.stack_status === stackStates.DELETE_IN_PROGRESS && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.undeployingPlan}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
bsStyle="danger"
|
||||||
|
now={stackDeletionProgress}
|
||||||
|
label={<span>{stackDeletionProgress + '%'}</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
{message && <pre>{message}</pre>}
|
||||||
|
<h2>
|
||||||
|
<FormattedMessage {...messages.resources} />
|
||||||
|
</h2>
|
||||||
|
<div className="flex-container">
|
||||||
|
<div className="flex-column">
|
||||||
|
<StackResourcesTable
|
||||||
|
isFetchingResources={!resourcesLoaded}
|
||||||
|
resources={resources.reverse()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
{!stack && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.undeployingPlan}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
bsStyle="danger"
|
||||||
|
now={100}
|
||||||
|
label={<span>{100 + '%'}</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
{message && <pre>{message}</pre>}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</Loader>
|
||||||
|
</ModalBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UndeployProgress.propTypes = {
|
||||||
|
deploymentStatus: PropTypes.object.isRequired,
|
||||||
|
fetchResources: PropTypes.func.isRequired,
|
||||||
|
fetchStacks: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object,
|
||||||
|
isFetchingStacks: PropTypes.bool.isRequired,
|
||||||
|
planName: PropTypes.string.isRequired,
|
||||||
|
resources: ImmutablePropTypes.list,
|
||||||
|
resourcesLoaded: PropTypes.bool.isRequired,
|
||||||
|
stack: ImmutablePropTypes.record,
|
||||||
|
stackDeletionProgress: PropTypes.number.isRequired,
|
||||||
|
stacksLoaded: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => ({
|
||||||
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
|
isFetchingStacks: state.stacks.isFetching,
|
||||||
|
resources: state.stacks.resources,
|
||||||
|
resourcesLoaded: state.stacks.resourcesLoaded,
|
||||||
|
stack: getCurrentStack(state),
|
||||||
|
stackDeletionProgress: getCurrentStackDeletionProgress(state),
|
||||||
|
stacksLoaded: state.stacks.isLoaded
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, { planName }) => ({
|
||||||
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
||||||
|
fetchResources: (stackName, stackId) =>
|
||||||
|
dispatch(StacksActions.fetchResources(stackName, stackId))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UndeployProgress);
|
@ -62,7 +62,7 @@ class DeleteStackButton extends React.Component {
|
|||||||
className="link btn btn-danger"
|
className="link btn btn-danger"
|
||||||
>
|
>
|
||||||
<InlineLoader
|
<InlineLoader
|
||||||
loaded={this.props.loaded}
|
loaded={!this.props.disabled}
|
||||||
content={formatMessage(messages.requestingDeletion)}
|
content={formatMessage(messages.requestingDeletion)}
|
||||||
inverse
|
inverse
|
||||||
>
|
>
|
||||||
@ -85,8 +85,7 @@ class DeleteStackButton extends React.Component {
|
|||||||
DeleteStackButton.propTypes = {
|
DeleteStackButton.propTypes = {
|
||||||
deleteStack: PropTypes.func.isRequired,
|
deleteStack: PropTypes.func.isRequired,
|
||||||
disabled: PropTypes.bool.isRequired,
|
disabled: PropTypes.bool.isRequired,
|
||||||
intl: PropTypes.object,
|
intl: PropTypes.object
|
||||||
loaded: PropTypes.bool.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default injectIntl(DeleteStackButton);
|
export default injectIntl(DeleteStackButton);
|
||||||
|
@ -24,6 +24,7 @@ import React from 'react';
|
|||||||
import DeploymentSuccess from './DeploymentSuccess';
|
import DeploymentSuccess from './DeploymentSuccess';
|
||||||
import DeploymentFailure from './DeploymentFailure';
|
import DeploymentFailure from './DeploymentFailure';
|
||||||
import DeploymentProgress from './DeploymentProgress';
|
import DeploymentProgress from './DeploymentProgress';
|
||||||
|
import UndeployProgress from './UndeployProgress';
|
||||||
import {
|
import {
|
||||||
deploymentStates,
|
deploymentStates,
|
||||||
deploymentStatusMessages
|
deploymentStatusMessages
|
||||||
@ -49,20 +50,20 @@ const messages = defineMessages({
|
|||||||
export const DeployStep = ({
|
export const DeployStep = ({
|
||||||
currentPlan,
|
currentPlan,
|
||||||
deploymentStatus,
|
deploymentStatus,
|
||||||
|
deploymentStatusUIError,
|
||||||
intl: { formatMessage },
|
intl: { formatMessage },
|
||||||
deploymentStatusUIError
|
isPendingDeploymentRequest
|
||||||
}) => {
|
}) => {
|
||||||
switch (deploymentStatus.status) {
|
switch (deploymentStatus.status) {
|
||||||
case deploymentStates.DEPLOYING:
|
case deploymentStates.DEPLOYING:
|
||||||
case deploymentStates.UNDEPLOYING:
|
|
||||||
return <DeploymentProgress planName={currentPlan.name} />;
|
return <DeploymentProgress planName={currentPlan.name} />;
|
||||||
|
case deploymentStates.UNDEPLOYING:
|
||||||
|
return <UndeployProgress planName={currentPlan.name} />;
|
||||||
case deploymentStates.DEPLOY_SUCCESS:
|
case deploymentStates.DEPLOY_SUCCESS:
|
||||||
return <DeploymentSuccess />;
|
return <DeploymentSuccess />;
|
||||||
case deploymentStates.DEPLOY_FAILED:
|
case deploymentStates.DEPLOY_FAILED:
|
||||||
return <DeploymentFailure planName={currentPlan.name} />;
|
|
||||||
case deploymentStates.UNDEPLOY_FAILED:
|
case deploymentStates.UNDEPLOY_FAILED:
|
||||||
// TODO(jtomasek): handle undeploy failure
|
return <DeploymentFailure planName={currentPlan.name} />;
|
||||||
return 'undeploy failed';
|
|
||||||
case deploymentStates.UNKNOWN:
|
case deploymentStates.UNKNOWN:
|
||||||
return (
|
return (
|
||||||
<InlineNotification
|
<InlineNotification
|
||||||
@ -74,16 +75,14 @@ export const DeployStep = ({
|
|||||||
</InlineNotification>
|
</InlineNotification>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
const disabled =
|
|
||||||
deploymentStatus.status === deploymentStates.STARTING_DEPLOYMENT;
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
to={`/plans/${currentPlan.name}/deployment-confirmation`}
|
to={`/plans/${currentPlan.name}/deployment-confirmation`}
|
||||||
className="btn btn-primary btn-lg link"
|
className="btn btn-primary btn-lg link"
|
||||||
disabled={disabled}
|
disabled={isPendingDeploymentRequest}
|
||||||
>
|
>
|
||||||
<InlineLoader
|
<InlineLoader
|
||||||
loaded={!disabled}
|
loaded={!isPendingDeploymentRequest}
|
||||||
content={formatMessage(messages.requestingDeploy)}
|
content={formatMessage(messages.requestingDeploy)}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.validateAndDeploy} />
|
<FormattedMessage {...messages.validateAndDeploy} />
|
||||||
@ -97,12 +96,15 @@ DeployStep.propTypes = {
|
|||||||
currentPlan: ImmutablePropTypes.record.isRequired,
|
currentPlan: ImmutablePropTypes.record.isRequired,
|
||||||
deploymentStatus: PropTypes.object.isRequired,
|
deploymentStatus: PropTypes.object.isRequired,
|
||||||
deploymentStatusUIError: PropTypes.string,
|
deploymentStatusUIError: PropTypes.string,
|
||||||
intl: PropTypes.object
|
intl: PropTypes.object,
|
||||||
|
isPendingDeploymentRequest: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
deploymentStatusUIError: getCurrentPlanDeploymentStatusUI(state).error
|
deploymentStatusUIError: getCurrentPlanDeploymentStatusUI(state).error,
|
||||||
|
isPendingDeploymentRequest: getCurrentPlanDeploymentStatusUI(state)
|
||||||
|
.isPendingRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
export default injectIntl(connect(mapStateToProps)(DeployStep));
|
export default injectIntl(connect(mapStateToProps)(DeployStep));
|
||||||
|
@ -22,9 +22,7 @@ import DeploymentConfirmation from '../deployment/DeploymentConfirmation';
|
|||||||
import { deploymentStates as ds } from '../../constants/DeploymentConstants';
|
import { deploymentStates as ds } from '../../constants/DeploymentConstants';
|
||||||
|
|
||||||
const DeploymentConfirmationRoute = ({ currentPlanName, deploymentStatus }) =>
|
const DeploymentConfirmationRoute = ({ currentPlanName, deploymentStatus }) =>
|
||||||
[ds.UNDEPLOYED, ds.UNKNOWN, ds.STARTING_DEPLOYMENT].includes(
|
[ds.UNDEPLOYED, ds.UNKNOWN].includes(deploymentStatus) ? (
|
||||||
deploymentStatus
|
|
||||||
) ? (
|
|
||||||
<DeploymentConfirmation />
|
<DeploymentConfirmation />
|
||||||
) : (
|
) : (
|
||||||
<Redirect to={`/plans/${currentPlanName}`} />
|
<Redirect to={`/plans/${currentPlanName}`} />
|
||||||
|
@ -22,7 +22,7 @@ import DeploymentDetail from '../deployment/DeploymentDetail';
|
|||||||
import { deploymentStates as ds } from '../../constants/DeploymentConstants';
|
import { deploymentStates as ds } from '../../constants/DeploymentConstants';
|
||||||
|
|
||||||
const DeploymentDetailRoute = ({ currentPlanName, deploymentStatus }) =>
|
const DeploymentDetailRoute = ({ currentPlanName, deploymentStatus }) =>
|
||||||
[ds.DEPLOYING, ds.UNDEPLOYING, ds.DEPLOY_FAILED].includes(
|
[ds.DEPLOYING, ds.UNDEPLOYING, ds.DEPLOY_FAILED, ds.UNDEPLOY_FAILED].includes(
|
||||||
deploymentStatus
|
deploymentStatus
|
||||||
) ? (
|
) ? (
|
||||||
<DeploymentDetail />
|
<DeploymentDetail />
|
||||||
|
@ -30,18 +30,10 @@ import {
|
|||||||
getCurrentStackDeploymentProgress,
|
getCurrentStackDeploymentProgress,
|
||||||
getCreateCompleteResources
|
getCreateCompleteResources
|
||||||
} from '../../selectors/stacks';
|
} from '../../selectors/stacks';
|
||||||
import { InlineLoader } from '../ui/Loader';
|
import { InlineLoader, Loader } from '../ui/Loader';
|
||||||
import StacksActions from '../../actions/StacksActions';
|
import StacksActions from '../../actions/StacksActions';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
cancelDeployment: {
|
|
||||||
id: 'DeploymentProgress.cancelDeployment',
|
|
||||||
defaultMessage: 'Cancel Deployment'
|
|
||||||
},
|
|
||||||
requestingDeletion: {
|
|
||||||
id: 'DeploymentProgress.requestingDeletion',
|
|
||||||
defaultMessage: 'Requesting Deletion of Deployment'
|
|
||||||
},
|
|
||||||
initializingDeployment: {
|
initializingDeployment: {
|
||||||
id: 'DeploymentProgress.initializingDeployment',
|
id: 'DeploymentProgress.initializingDeployment',
|
||||||
defaultMessage: 'Initializing {planName} plan deployment'
|
defaultMessage: 'Initializing {planName} plan deployment'
|
||||||
@ -66,10 +58,10 @@ class DeploymentProgress extends React.Component {
|
|||||||
this.fetchStacks();
|
this.fetchStacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!this.props.stack && newProps.stack) {
|
if (!prevProps.stack && this.props.stack) {
|
||||||
const { stack: { stack_name, id } } = newProps;
|
const { stack: { stack_name, id }, fetchResources } = this.props;
|
||||||
this.props.fetchResources(stack_name, id);
|
fetchResources(stack_name, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +77,8 @@ class DeploymentProgress extends React.Component {
|
|||||||
resourcesCount,
|
resourcesCount,
|
||||||
completeResourcesCount,
|
completeResourcesCount,
|
||||||
stackDeploymentProgress,
|
stackDeploymentProgress,
|
||||||
stack
|
stack,
|
||||||
|
stacksLoaded
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -101,6 +94,7 @@ class DeploymentProgress extends React.Component {
|
|||||||
<FormattedMessage {...messages.viewInformation} />
|
<FormattedMessage {...messages.viewInformation} />
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
<Loader loaded={stacksLoaded}>
|
||||||
{!stack && (
|
{!stack && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="progress-description">
|
<div className="progress-description">
|
||||||
@ -153,6 +147,7 @@ class DeploymentProgress extends React.Component {
|
|||||||
{message && <pre>{message}</pre>}
|
{message && <pre>{message}</pre>}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
</Loader>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -168,7 +163,8 @@ DeploymentProgress.propTypes = {
|
|||||||
planName: PropTypes.string.isRequired,
|
planName: PropTypes.string.isRequired,
|
||||||
resourcesCount: PropTypes.number,
|
resourcesCount: PropTypes.number,
|
||||||
stack: ImmutablePropTypes.record,
|
stack: ImmutablePropTypes.record,
|
||||||
stackDeploymentProgress: PropTypes.number.isRequired
|
stackDeploymentProgress: PropTypes.number.isRequired,
|
||||||
|
stacksLoaded: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
@ -176,12 +172,12 @@ const mapStateToProps = (state, props) => ({
|
|||||||
stack: getCurrentStack(state),
|
stack: getCurrentStack(state),
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
isFetchingStacks: state.stacks.isFetching,
|
isFetchingStacks: state.stacks.isFetching,
|
||||||
|
stacksLoaded: state.stacks.isLoaded,
|
||||||
stackDeploymentProgress: getCurrentStackDeploymentProgress(state),
|
stackDeploymentProgress: getCurrentStackDeploymentProgress(state),
|
||||||
resourcesCount: state.stacks.resources.size
|
resourcesCount: state.stacks.resources.size
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { planName }) => ({
|
const mapDispatchToProps = (dispatch, { planName }) => ({
|
||||||
deleteStack: () => dispatch(StacksActions.deleteStack(planName, '')),
|
|
||||||
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
||||||
fetchResources: (stackName, stackId) =>
|
fetchResources: (stackName, stackId) =>
|
||||||
dispatch(StacksActions.fetchResources(stackName, stackId))
|
dispatch(StacksActions.fetchResources(stackName, stackId))
|
||||||
|
@ -22,11 +22,16 @@ import React, { Fragment } from 'react';
|
|||||||
|
|
||||||
import DeleteStackButton from './DeleteStackButton';
|
import DeleteStackButton from './DeleteStackButton';
|
||||||
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
|
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
|
||||||
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
import {
|
||||||
|
getCurrentPlanDeploymentStatus,
|
||||||
|
getCurrentPlanDeploymentStatusUI
|
||||||
|
} from '../../selectors/deployment';
|
||||||
import { getCurrentStack, getOvercloudInfo } from '../../selectors/stacks';
|
import { getCurrentStack, getOvercloudInfo } from '../../selectors/stacks';
|
||||||
|
import { getCurrentPlanName } from '../../selectors/plans';
|
||||||
import InlineNotification from '../ui/InlineNotification';
|
import InlineNotification from '../ui/InlineNotification';
|
||||||
import OvercloudInfo from '../deployment/OvercloudInfo';
|
import OvercloudInfo from '../deployment/OvercloudInfo';
|
||||||
import { Loader } from '../ui/Loader';
|
import { Loader } from '../ui/Loader';
|
||||||
|
import { startUndeploy } from '../../actions/DeploymentActions';
|
||||||
import StacksActions from '../../actions/StacksActions';
|
import StacksActions from '../../actions/StacksActions';
|
||||||
|
|
||||||
class DeploymentSuccess extends React.Component {
|
class DeploymentSuccess extends React.Component {
|
||||||
@ -43,12 +48,13 @@ class DeploymentSuccess extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
intl: { formatMessage },
|
intl: { formatMessage },
|
||||||
|
isPendingRequest,
|
||||||
stack,
|
stack,
|
||||||
stacksLoaded,
|
stacksLoaded,
|
||||||
overcloudInfo,
|
overcloudInfo,
|
||||||
deleteStack,
|
planName,
|
||||||
deploymentStatus: { status, message },
|
undeployPlan,
|
||||||
isRequestingStackDelete
|
deploymentStatus: { status, message }
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -67,9 +73,8 @@ class DeploymentSuccess extends React.Component {
|
|||||||
fetchOvercloudInfo={this.fetchOvercloudInfo.bind(this)}
|
fetchOvercloudInfo={this.fetchOvercloudInfo.bind(this)}
|
||||||
/>
|
/>
|
||||||
<DeleteStackButton
|
<DeleteStackButton
|
||||||
deleteStack={deleteStack.bind(this, stack)}
|
deleteStack={undeployPlan.bind(this, planName)}
|
||||||
disabled={isRequestingStackDelete}
|
disabled={isPendingRequest}
|
||||||
loaded={!isRequestingStackDelete}
|
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
@ -79,28 +84,30 @@ class DeploymentSuccess extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeploymentSuccess.propTypes = {
|
DeploymentSuccess.propTypes = {
|
||||||
deleteStack: PropTypes.func.isRequired,
|
|
||||||
deploymentStatus: ImmutablePropTypes.record.isRequired,
|
deploymentStatus: ImmutablePropTypes.record.isRequired,
|
||||||
fetchStackEnvironment: PropTypes.func.isRequired,
|
fetchStackEnvironment: PropTypes.func.isRequired,
|
||||||
fetchStackResource: PropTypes.func.isRequired,
|
fetchStackResource: PropTypes.func.isRequired,
|
||||||
fetchStacks: PropTypes.func.isRequired,
|
fetchStacks: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object,
|
intl: PropTypes.object,
|
||||||
isRequestingStackDelete: PropTypes.bool,
|
isPendingRequest: PropTypes.bool.isRequired,
|
||||||
overcloudInfo: ImmutablePropTypes.map.isRequired,
|
overcloudInfo: ImmutablePropTypes.map.isRequired,
|
||||||
|
planName: PropTypes.string.isRequired,
|
||||||
stack: ImmutablePropTypes.record,
|
stack: ImmutablePropTypes.record,
|
||||||
stacksLoaded: PropTypes.bool.isRequired
|
stacksLoaded: PropTypes.bool.isRequired,
|
||||||
|
undeployPlan: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
isRequestingStackDelete: state.stacks.isRequestingStackDelete,
|
planName: getCurrentPlanName(state),
|
||||||
overcloudInfo: getOvercloudInfo(state),
|
overcloudInfo: getOvercloudInfo(state),
|
||||||
stack: getCurrentStack(state),
|
stack: getCurrentStack(state),
|
||||||
stacksLoaded: state.stacks.isLoaded
|
stacksLoaded: state.stacks.isLoaded,
|
||||||
|
isPendingRequest: getCurrentPlanDeploymentStatusUI(state).isPendingRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
deleteStack: planName => dispatch(StacksActions.deleteStack(planName, '')),
|
undeployPlan: planName => dispatch(startUndeploy(planName)),
|
||||||
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
||||||
fetchStackEnvironment: stack =>
|
fetchStackEnvironment: stack =>
|
||||||
dispatch(StacksActions.fetchEnvironment(stack)),
|
dispatch(StacksActions.fetchEnvironment(stack)),
|
||||||
|
183
src/js/components/deployment_plan/UndeployProgress.js
Normal file
183
src/js/components/deployment_plan/UndeployProgress.js
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ProgressBar } from 'react-bootstrap';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
|
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
|
||||||
|
import { stackStates } from '../../constants/StacksConstants';
|
||||||
|
import { getCurrentPlanDeploymentStatus } from '../../selectors/deployment';
|
||||||
|
import {
|
||||||
|
getCurrentStack,
|
||||||
|
getCurrentStackDeletionProgress,
|
||||||
|
getDeleteCompleteResources
|
||||||
|
} from '../../selectors/stacks';
|
||||||
|
import { InlineLoader, Loader } from '../ui/Loader';
|
||||||
|
import StacksActions from '../../actions/StacksActions';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
initializingUndeploy: {
|
||||||
|
id: 'UndeployProgress.initializingUndeploy',
|
||||||
|
defaultMessage: 'Initializing {planName} plan deployment deletion'
|
||||||
|
},
|
||||||
|
viewInformation: {
|
||||||
|
id: 'UndeployProgress.viewInformation',
|
||||||
|
defaultMessage: 'View detailed information'
|
||||||
|
},
|
||||||
|
undeployingPlan: {
|
||||||
|
id: 'UndeployProgress.undeployingPlan',
|
||||||
|
defaultMessage: 'Deleting {planName} plan deployment'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class UndeployProgress extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchStacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (!prevProps.stack && this.props.stack) {
|
||||||
|
const { stack: { stack_name, id }, fetchResources } = this.props;
|
||||||
|
fetchResources(stack_name, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchStacks() {
|
||||||
|
const { fetchStacks, isFetchingStacks } = this.props;
|
||||||
|
!isFetchingStacks && fetchStacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
deploymentStatus: { status, message },
|
||||||
|
planName,
|
||||||
|
stackDeletionProgress,
|
||||||
|
stack,
|
||||||
|
stacksLoaded
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
{...deploymentStatusMessages[status]}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</span>{' '}
|
||||||
|
<Link to={`/plans/${planName}/deployment-detail`}>
|
||||||
|
<FormattedMessage {...messages.viewInformation} />
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<Loader loaded={stacksLoaded}>
|
||||||
|
{stack &&
|
||||||
|
stack.stack_status !== stackStates.DELETE_IN_PROGRESS && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.initializingUndeploy}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
now={0}
|
||||||
|
label={<span>0%</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
{stack &&
|
||||||
|
stack.stack_status === stackStates.DELETE_IN_PROGRESS && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.undeployingPlan}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
bsStyle="danger"
|
||||||
|
now={stackDeletionProgress}
|
||||||
|
label={<span>{stackDeletionProgress + '%'}</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
{message && <pre>{message}</pre>}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
{!stack && (
|
||||||
|
<Fragment>
|
||||||
|
<div className="progress-description">
|
||||||
|
<InlineLoader />
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.undeployingPlan}
|
||||||
|
values={{ planName: <strong>{planName}</strong> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
bsStyle="danger"
|
||||||
|
now={100}
|
||||||
|
label={<span>{100 + '%'}</span>}
|
||||||
|
className="progress-label-top-right"
|
||||||
|
/>
|
||||||
|
{message && <pre>{message}</pre>}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</Loader>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UndeployProgress.propTypes = {
|
||||||
|
deletedResourcesCount: PropTypes.number,
|
||||||
|
deploymentStatus: PropTypes.object.isRequired,
|
||||||
|
fetchResources: PropTypes.func.isRequired,
|
||||||
|
fetchStacks: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object,
|
||||||
|
isFetchingStacks: PropTypes.bool.isRequired,
|
||||||
|
planName: PropTypes.string.isRequired,
|
||||||
|
resourcesCount: PropTypes.number,
|
||||||
|
stack: ImmutablePropTypes.record,
|
||||||
|
stackDeletionProgress: PropTypes.number.isRequired,
|
||||||
|
stacksLoaded: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => ({
|
||||||
|
deletedResourcesCount: getDeleteCompleteResources(state).size,
|
||||||
|
deploymentStatus: getCurrentPlanDeploymentStatus(state),
|
||||||
|
isFetchingStacks: state.stacks.isFetching,
|
||||||
|
stack: getCurrentStack(state),
|
||||||
|
stacksLoaded: state.stacks.isLoaded,
|
||||||
|
stackDeletionProgress: getCurrentStackDeletionProgress(state),
|
||||||
|
resourcesCount: state.stacks.resources.size
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, { planName }) => ({
|
||||||
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
||||||
|
fetchResources: (stackName, stackId) =>
|
||||||
|
dispatch(StacksActions.fetchResources(stackName, stackId))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default injectIntl(
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)(UndeployProgress)
|
||||||
|
);
|
@ -26,11 +26,15 @@ export const START_DEPLOYMENT_SUCCESS = 'START_DEPLOYMENT_SUCCESS';
|
|||||||
export const START_DEPLOYMENT_PENDING = 'START_DEPLOYMENT_PENDING';
|
export const START_DEPLOYMENT_PENDING = 'START_DEPLOYMENT_PENDING';
|
||||||
export const DEPLOYMENT_FAILED = 'DEPLOYMENT_FAILED';
|
export const DEPLOYMENT_FAILED = 'DEPLOYMENT_FAILED';
|
||||||
export const DEPLOYMENT_SUCCESS = 'DEPLOYMENT_SUCCESS';
|
export const DEPLOYMENT_SUCCESS = 'DEPLOYMENT_SUCCESS';
|
||||||
|
export const START_UNDEPLOY_FAILED = 'START_UNDEPLOY_FAILED';
|
||||||
|
export const START_UNDEPLOY_SUCCESS = 'START_UNDEPLOY_SUCCESS';
|
||||||
|
export const START_UNDEPLOY_PENDING = 'START_UNDEPLOY_PENDING';
|
||||||
|
export const UNDEPLOY_FAILED = 'UNDEPLOY_FAILED';
|
||||||
|
export const UNDEPLOY_SUCCESS = 'UNDEPLOY_SUCCESS';
|
||||||
|
|
||||||
export const deploymentStates = keyMirror({
|
export const deploymentStates = keyMirror({
|
||||||
UNDEPLOYED: null,
|
UNDEPLOYED: null,
|
||||||
DEPLOY_SUCCESS: null,
|
DEPLOY_SUCCESS: null,
|
||||||
STARTING_DEPLOYMENT: null,
|
|
||||||
DEPLOYING: null,
|
DEPLOYING: null,
|
||||||
UNDEPLOYING: null,
|
UNDEPLOYING: null,
|
||||||
DEPLOY_FAILED: null,
|
DEPLOY_FAILED: null,
|
||||||
@ -53,7 +57,8 @@ export const deploymentStatusMessages = defineMessages({
|
|||||||
},
|
},
|
||||||
UNDEPLOYING: {
|
UNDEPLOYING: {
|
||||||
id: 'DeploymentStatus.undeploying',
|
id: 'DeploymentStatus.undeploying',
|
||||||
defaultMessage: 'Undeploy in progress'
|
defaultMessage:
|
||||||
|
'Deletion of {planName} plan deployment is currently in progress'
|
||||||
},
|
},
|
||||||
DEPLOY_FAILED: {
|
DEPLOY_FAILED: {
|
||||||
id: 'DeploymentStatus.deploymentFailed',
|
id: 'DeploymentStatus.deploymentFailed',
|
||||||
|
@ -30,7 +30,7 @@ export default {
|
|||||||
DEPLOYMENT_DEPLOY_PLAN: 'tripleo.deployment.v1.deploy_plan',
|
DEPLOYMENT_DEPLOY_PLAN: 'tripleo.deployment.v1.deploy_plan',
|
||||||
UNDEPLOY_PLAN: 'tripleo.deployment.v1.undeploy_plan',
|
UNDEPLOY_PLAN: 'tripleo.deployment.v1.undeploy_plan',
|
||||||
DOWNLOAD_LOGS: 'tripleo.plan_management.v1.download_logs',
|
DOWNLOAD_LOGS: 'tripleo.plan_management.v1.download_logs',
|
||||||
HEAT_STACKS_GET: 'tripleo.stack.v1._heat_stacks_get',
|
HEAT_STACKS_LIST: 'tripleo.stack.v1._heat_stacks_list',
|
||||||
NETWORK_LIST: 'tripleo.plan_management.v1.list_networks',
|
NETWORK_LIST: 'tripleo.plan_management.v1.list_networks',
|
||||||
PARAMETERS_GET: 'tripleo.parameters.get_flatten',
|
PARAMETERS_GET: 'tripleo.parameters.get_flatten',
|
||||||
PARAMETERS_UPDATE: 'tripleo.parameters.update',
|
PARAMETERS_UPDATE: 'tripleo.parameters.update',
|
||||||
|
@ -18,9 +18,6 @@ import keyMirror from 'keymirror';
|
|||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
export default keyMirror({
|
export default keyMirror({
|
||||||
DELETE_STACK_PENDING: null,
|
|
||||||
DELETE_STACK_FAILED: null,
|
|
||||||
DELETE_STACK_SUCCESS: null,
|
|
||||||
FETCH_STACK_ENVIRONMENT_SUCCESS: null,
|
FETCH_STACK_ENVIRONMENT_SUCCESS: null,
|
||||||
FETCH_STACK_ENVIRONMENT_PENDING: null,
|
FETCH_STACK_ENVIRONMENT_PENDING: null,
|
||||||
FETCH_STACK_ENVIRONMENT_FAILED: null,
|
FETCH_STACK_ENVIRONMENT_FAILED: null,
|
||||||
|
@ -28,5 +28,6 @@ export const DeploymentStatus = Record({
|
|||||||
export const DeploymentStatusUI = Record({
|
export const DeploymentStatusUI = Record({
|
||||||
error: undefined,
|
error: undefined,
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
isFetching: false
|
isFetching: false,
|
||||||
|
isPendingRequest: false
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,6 @@ import { List, Map, Record } from 'immutable';
|
|||||||
|
|
||||||
export const StacksState = Record({
|
export const StacksState = Record({
|
||||||
currentStackEnvironment: Map(),
|
currentStackEnvironment: Map(),
|
||||||
isRequestingStackDelete: false,
|
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isFetchingResources: false,
|
isFetchingResources: false,
|
||||||
|
@ -27,6 +27,11 @@ import {
|
|||||||
START_DEPLOYMENT_FAILED,
|
START_DEPLOYMENT_FAILED,
|
||||||
START_DEPLOYMENT_PENDING,
|
START_DEPLOYMENT_PENDING,
|
||||||
START_DEPLOYMENT_SUCCESS,
|
START_DEPLOYMENT_SUCCESS,
|
||||||
|
START_UNDEPLOY_FAILED,
|
||||||
|
START_UNDEPLOY_PENDING,
|
||||||
|
START_UNDEPLOY_SUCCESS,
|
||||||
|
UNDEPLOY_FAILED,
|
||||||
|
UNDEPLOY_SUCCESS,
|
||||||
deploymentStates
|
deploymentStates
|
||||||
} from '../constants/DeploymentConstants';
|
} from '../constants/DeploymentConstants';
|
||||||
import {
|
import {
|
||||||
@ -51,24 +56,11 @@ export const deploymentStatusByPlan = (state = Map(), { type, payload }) => {
|
|||||||
messages.push(payload.message)
|
messages.push(payload.message)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
case START_DEPLOYMENT_PENDING:
|
|
||||||
return state.set(
|
|
||||||
payload,
|
|
||||||
new DeploymentStatus({ status: deploymentStates.STARTING_DEPLOYMENT })
|
|
||||||
);
|
|
||||||
case START_DEPLOYMENT_SUCCESS:
|
case START_DEPLOYMENT_SUCCESS:
|
||||||
return state.set(
|
return state.set(
|
||||||
payload,
|
payload,
|
||||||
new DeploymentStatus({ status: deploymentStates.DEPLOYING })
|
new DeploymentStatus({ status: deploymentStates.DEPLOYING })
|
||||||
);
|
);
|
||||||
case START_DEPLOYMENT_FAILED:
|
|
||||||
return state.set(
|
|
||||||
payload.planName,
|
|
||||||
new DeploymentStatus({
|
|
||||||
status: deploymentStates.UNDEPLOYED,
|
|
||||||
message: payload.message
|
|
||||||
})
|
|
||||||
);
|
|
||||||
case DEPLOYMENT_SUCCESS:
|
case DEPLOYMENT_SUCCESS:
|
||||||
return state.set(
|
return state.set(
|
||||||
payload.planName,
|
payload.planName,
|
||||||
@ -85,6 +77,27 @@ export const deploymentStatusByPlan = (state = Map(), { type, payload }) => {
|
|||||||
message: payload.message
|
message: payload.message
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
case START_UNDEPLOY_SUCCESS:
|
||||||
|
return state.set(
|
||||||
|
payload,
|
||||||
|
new DeploymentStatus({ status: deploymentStates.UNDEPLOYING })
|
||||||
|
);
|
||||||
|
case UNDEPLOY_SUCCESS:
|
||||||
|
return state.set(
|
||||||
|
payload.planName,
|
||||||
|
new DeploymentStatus({
|
||||||
|
status: deploymentStates.UNDEPLOYED,
|
||||||
|
message: payload.message
|
||||||
|
})
|
||||||
|
);
|
||||||
|
case UNDEPLOY_FAILED:
|
||||||
|
return state.set(
|
||||||
|
payload.planName,
|
||||||
|
new DeploymentStatus({
|
||||||
|
status: deploymentStates.UNDEPLOY_FAILED,
|
||||||
|
message: payload.message
|
||||||
|
})
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -112,6 +125,14 @@ export const deploymentStatusUI = (state = Map(), { type, payload }) => {
|
|||||||
error: undefined
|
error: undefined
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
case START_DEPLOYMENT_PENDING:
|
||||||
|
case START_UNDEPLOY_PENDING:
|
||||||
|
return state.setIn([payload, 'isPendingRequest'], true);
|
||||||
|
case START_DEPLOYMENT_SUCCESS:
|
||||||
|
case START_DEPLOYMENT_FAILED:
|
||||||
|
case START_UNDEPLOY_SUCCESS:
|
||||||
|
case START_UNDEPLOY_FAILED:
|
||||||
|
return state.setIn([payload, 'isPendingRequest'], false);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { fromJS, Map } from 'immutable';
|
import { fromJS, Map } from 'immutable';
|
||||||
|
|
||||||
import { Stack, StackResource, StacksState } from '../immutableRecords/stacks';
|
import { Stack, StackResource, StacksState } from '../immutableRecords/stacks';
|
||||||
import StacksConstants, { stackStates } from '../constants/StacksConstants';
|
import StacksConstants from '../constants/StacksConstants';
|
||||||
import PlansConstants from '../constants/PlansConstants';
|
import PlansConstants from '../constants/PlansConstants';
|
||||||
|
|
||||||
const initialState = new StacksState();
|
const initialState = new StacksState();
|
||||||
@ -90,20 +90,6 @@ export default function stacksReducer(state = initialState, action) {
|
|||||||
case PlansConstants.PLAN_CHOSEN:
|
case PlansConstants.PLAN_CHOSEN:
|
||||||
return initialState;
|
return initialState;
|
||||||
|
|
||||||
case StacksConstants.DELETE_STACK_SUCCESS:
|
|
||||||
return state
|
|
||||||
.set('isRequestingStackDelete', false)
|
|
||||||
.setIn(
|
|
||||||
['stacks', action.payload, 'stack_status'],
|
|
||||||
stackStates.DELETE_IN_PROGRESS
|
|
||||||
);
|
|
||||||
|
|
||||||
case StacksConstants.DELETE_STACK_FAILED:
|
|
||||||
return state.set('isRequestingStackDelete', false);
|
|
||||||
|
|
||||||
case StacksConstants.DELETE_STACK_PENDING:
|
|
||||||
return state.set('isRequestingStackDelete', true);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,11 @@ export const getCreateCompleteResources = createSelector(
|
|||||||
resources => resources.filter(r => r.resource_status === 'CREATE_COMPLETE')
|
resources => resources.filter(r => r.resource_status === 'CREATE_COMPLETE')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getDeleteCompleteResources = createSelector(
|
||||||
|
[stackResourcesSelector],
|
||||||
|
resources => resources.filter(r => r.resource_status === 'DELETE_COMPLETE')
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns calculated percentage of deployment progress
|
* Returns calculated percentage of deployment progress
|
||||||
*/
|
*/
|
||||||
@ -71,6 +76,20 @@ export const getCurrentStackDeploymentProgress = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns calculated percentage of deletion progress
|
||||||
|
*/
|
||||||
|
export const getCurrentStackDeletionProgress = createSelector(
|
||||||
|
[stackResourcesSelector, getDeleteCompleteResources],
|
||||||
|
(resources, completeResources) => {
|
||||||
|
let allResources = resources.size;
|
||||||
|
if (allResources > 0) {
|
||||||
|
return Math.ceil(completeResources.size / allResources * 100);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Map containing the overcloud information.
|
* Returns a Map containing the overcloud information.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user