314 lines
12 KiB
JavaScript
314 lines
12 KiB
JavaScript
/*
|
|
* Copyright 2016 Mirantis, 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 _ from 'underscore';
|
|
import i18n from 'i18n';
|
|
import React from 'react';
|
|
import ReactTransitionGroup from 'react-addons-transition-group';
|
|
import models from 'models';
|
|
import utils from 'utils';
|
|
import {Link, ScreenTransitionWrapper} from 'views/controls';
|
|
import DeploymentHistory from 'views/cluster_page_tabs/deployment_history_component';
|
|
|
|
var HistoryTab, DeploymentHistoryScreen;
|
|
|
|
HistoryTab = React.createClass({
|
|
statics: {
|
|
breadcrumbsPath() {
|
|
return [
|
|
[i18n('cluster_page.tabs.history'), null, {active: true}]
|
|
];
|
|
},
|
|
getSubtabs({cluster}) {
|
|
return _.map(cluster.get('transactions').filterTasks({active: false}), 'id');
|
|
},
|
|
checkSubroute(tabProps) {
|
|
var {activeTab, cluster, tabOptions} = tabProps;
|
|
var subtabs = this.getSubtabs(tabProps);
|
|
var defaultSubtab = _.last(subtabs);
|
|
if (activeTab === 'history') {
|
|
var transactionId = Number(tabOptions[0]);
|
|
if (!transactionId || !_.includes(subtabs, transactionId)) {
|
|
app.navigate(
|
|
'/cluster/' + cluster.id + '/history' + (defaultSubtab ? '/' + defaultSubtab : ''),
|
|
{replace: true}
|
|
);
|
|
}
|
|
return {activeTransactionId: transactionId || null};
|
|
}
|
|
return {activeTransactionId: defaultSubtab || null};
|
|
}
|
|
},
|
|
getInitialState() {
|
|
return {
|
|
loading: !!this.props.cluster.get('transactions').findTask({active: false}),
|
|
deploymentHistory: null
|
|
};
|
|
},
|
|
loadScreenData(transactionId) {
|
|
transactionId = transactionId || this.props.activeTransactionId;
|
|
if (_.isNull(transactionId)) return Promise.resolve();
|
|
|
|
return DeploymentHistoryScreen
|
|
.fetchData(transactionId)
|
|
.then(
|
|
({deploymentHistory}) => {
|
|
this.setState({loading: false, deploymentHistory});
|
|
},
|
|
() => {
|
|
app.navigate(
|
|
'/cluster/' + this.props.cluster.id + '/history',
|
|
{replace: true}
|
|
);
|
|
}
|
|
);
|
|
},
|
|
componentDidMount() {
|
|
this.loadScreenData();
|
|
},
|
|
componentWillReceiveProps({cluster, activeTransactionId}) {
|
|
var transaction = _.last(cluster.get('transactions').filterTasks({active: false}));
|
|
if (_.isNull(this.props.activeTransactionId) && transaction) {
|
|
app.navigate(
|
|
'/cluster/' + cluster.id + '/history/' + transaction.id,
|
|
{replace: true}
|
|
);
|
|
}
|
|
if (this.props.activeTransactionId !== activeTransactionId) {
|
|
this.setState({loading: true, deploymentHistory: null});
|
|
this.loadScreenData(activeTransactionId);
|
|
}
|
|
},
|
|
renderTransactionTitle(transaction) {
|
|
var graphType = transaction.get('graph_type');
|
|
return [
|
|
!_.isNull(graphType) &&
|
|
<span key='graph'>
|
|
{i18n('cluster_page.history_tab.graph_titles.' + graphType, {defaultValue: graphType})}
|
|
</span>,
|
|
<span key='time' className='time-start'>
|
|
{transaction.get('time_start') ?
|
|
utils.formatTimestamp(utils.parseISO8601Date(transaction.get('time_start')), false)
|
|
:
|
|
'#' + transaction.id
|
|
}
|
|
</span>
|
|
];
|
|
},
|
|
render() {
|
|
var {cluster, activeTransactionId} = this.props;
|
|
var {deploymentHistory} = this.state;
|
|
var ns = 'cluster_page.history_tab.';
|
|
var transactions = cluster.get('transactions').filterTasks({active: false});
|
|
var activeTransaction = cluster.get('transactions').get(activeTransactionId);
|
|
var activeTransactionGraphType = activeTransaction && activeTransaction.get('graph_type');
|
|
var visibleTransactionsAmount = 7;
|
|
var visibleTransactions = transactions;
|
|
var hiddenTransactions = [];
|
|
var activeHiddenTransaction;
|
|
if (transactions.length > visibleTransactionsAmount) {
|
|
visibleTransactions = _.takeRight(transactions, visibleTransactionsAmount - 1);
|
|
hiddenTransactions = _.take(transactions,
|
|
transactions.length - (visibleTransactionsAmount - 1)
|
|
).reverse();
|
|
activeHiddenTransaction = _.find(hiddenTransactions, {id: activeTransactionId});
|
|
}
|
|
|
|
return (
|
|
<div className='row'>
|
|
<div className='title col-xs-12'>
|
|
{i18n(ns + 'title')}
|
|
</div>
|
|
<div className='wrapper col-xs-12'>
|
|
{transactions.length ?
|
|
<div>
|
|
<div className='transaction-list clearfix'>
|
|
{!!hiddenTransactions.length &&
|
|
<div>
|
|
<div className='dropdown'>
|
|
<button
|
|
className={utils.classNames({
|
|
'btn btn-default dropdown-toggle': true,
|
|
[activeHiddenTransaction && activeHiddenTransaction.get('status')]:
|
|
activeHiddenTransaction,
|
|
active: activeHiddenTransaction
|
|
})}
|
|
id='previous-transactions'
|
|
data-toggle='dropdown'
|
|
>
|
|
{activeHiddenTransaction ?
|
|
this.renderTransactionTitle(activeHiddenTransaction)
|
|
:
|
|
<span className='previous-deployments'>
|
|
{i18n(ns + 'previous_deployments')}
|
|
</span>
|
|
}
|
|
<span className='caret' />
|
|
</button>
|
|
<ul className='dropdown-menu'>
|
|
{_.map(
|
|
_.reject(hiddenTransactions, {id: activeTransactionId}),
|
|
(transaction) => {
|
|
return (
|
|
<li key={transaction.id}>
|
|
<Link
|
|
to={'/cluster/' + cluster.id + '/history/' + transaction.id}
|
|
className={transaction.get('status')}
|
|
>
|
|
{this.renderTransactionTitle(transaction)}
|
|
</Link>
|
|
</li>
|
|
);
|
|
}
|
|
)}
|
|
</ul>
|
|
</div>
|
|
<i className='glyphicon glyphicon-arrow-right' />
|
|
</div>
|
|
}
|
|
{_.map(visibleTransactions, (transaction, index) => {
|
|
return (
|
|
<div key={transaction.id}>
|
|
<Link
|
|
to={'/cluster/' + cluster.id + '/history/' + transaction.id}
|
|
className={utils.classNames({
|
|
'transaction-link': true,
|
|
[transaction.get('status')]: true,
|
|
active: transaction.id === activeTransactionId
|
|
})}
|
|
>
|
|
{this.renderTransactionTitle(transaction)}
|
|
</Link>
|
|
{index < visibleTransactions.length - 1 &&
|
|
<i className='glyphicon glyphicon-arrow-right' />
|
|
}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
<div
|
|
className={utils.classNames('transaction-summary', activeTransaction.get('status'))}
|
|
>
|
|
<div className='row'>
|
|
<div className='col-xs-2 transaction-summary-label'>
|
|
{i18n(
|
|
ns + 'transaction_attributes.' +
|
|
(_.isNull(activeTransactionGraphType) ? 'name' : 'graph_type')
|
|
)}
|
|
</div>
|
|
<div className='col-xs-4'>
|
|
{_.isNull(activeTransactionGraphType) ?
|
|
activeTransaction.get('name')
|
|
:
|
|
i18n(
|
|
ns + 'graph_titles.' + activeTransactionGraphType,
|
|
{defaultValue: activeTransactionGraphType}
|
|
)
|
|
}
|
|
{activeTransaction.get('dry_run') &&
|
|
<div className='dry-run-label label label-default'>
|
|
{i18n(ns + 'transaction_attributes.dry_run')}
|
|
</div>
|
|
}
|
|
</div>
|
|
{activeTransaction.get('time_start') && [
|
|
<div key='time-start-label' className='col-xs-2 transaction-summary-label'>
|
|
{i18n(ns + 'transaction_attributes.time_start')}
|
|
</div>,
|
|
<div key='time-start-value' className='col-xs-4'>
|
|
{utils.formatTimestamp(
|
|
utils.parseISO8601Date(activeTransaction.get('time_start'))
|
|
)}
|
|
</div>
|
|
]}
|
|
</div>
|
|
<div className='row'>
|
|
<div className='col-xs-2 transaction-summary-label'>
|
|
{i18n(ns + 'transaction_attributes.status')}
|
|
</div>
|
|
<div className='col-xs-4 status'>
|
|
{i18n(
|
|
ns + 'transaction_statuses.' + activeTransaction.get('status'),
|
|
{defaultValue: activeTransaction.get('status')}
|
|
)}
|
|
</div>
|
|
{activeTransaction.get('time_end') && [
|
|
<div key='time-end-label' className='col-xs-2 transaction-summary-label'>
|
|
{i18n(ns + 'transaction_attributes.time_end')}
|
|
</div>,
|
|
<div key='time-end-value' className='col-xs-4'>
|
|
{utils.formatTimestamp(
|
|
utils.parseISO8601Date(activeTransaction.get('time_end'))
|
|
)}
|
|
</div>
|
|
]}
|
|
</div>
|
|
<div className='row'>
|
|
<div className='col-xs-2 transaction-summary-label'>
|
|
{i18n(ns + 'transaction_attributes.message')}
|
|
</div>
|
|
<div
|
|
className='col-xs-10 transaction-summary-value message'
|
|
dangerouslySetInnerHTML={{
|
|
__html: utils.urlify(activeTransaction.escape('message'))
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
{!_.isNull(deploymentHistory) &&
|
|
<ReactTransitionGroup
|
|
component='div'
|
|
transitionName='screen'
|
|
>
|
|
<ScreenTransitionWrapper key={screen} loading={this.state.loading}>
|
|
<DeploymentHistoryScreen
|
|
ref='screen'
|
|
deploymentHistory={deploymentHistory}
|
|
transaction={cluster.get('transactions').get(activeTransactionId)}
|
|
cluster={cluster}
|
|
nodes={cluster.get('nodes')}
|
|
nodeNetworkGroups={cluster.get('nodeNetworkGroups')}
|
|
/>
|
|
</ScreenTransitionWrapper>
|
|
</ReactTransitionGroup>
|
|
}
|
|
</div>
|
|
:
|
|
<div className='alert alert-warning'>
|
|
{i18n(ns + 'no_finished_deployment_alert')}
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
DeploymentHistoryScreen = React.createClass({
|
|
statics: {
|
|
fetchData(transactionId) {
|
|
var deploymentHistory = new models.DeploymentTasks();
|
|
deploymentHistory.url = '/api/transactions/' + transactionId + '/deployment_history';
|
|
return deploymentHistory.fetch()
|
|
.then(() => ({deploymentHistory}));
|
|
}
|
|
},
|
|
render() {
|
|
return <DeploymentHistory {...this.props} width={1128} />;
|
|
}
|
|
});
|
|
|
|
export default HistoryTab;
|