diff --git a/packages/apollo/src/components/JoinChannelModal/JoinChannelModal.js b/packages/apollo/src/components/JoinChannelModal/JoinChannelModal.js index 02db2bf6..e151c3ed 100644 --- a/packages/apollo/src/components/JoinChannelModal/JoinChannelModal.js +++ b/packages/apollo/src/components/JoinChannelModal/JoinChannelModal.js @@ -26,6 +26,7 @@ import { EventsRestApi } from '../../rest/EventsRestApi'; import { MspRestApi } from '../../rest/MspRestApi'; import { OrdererRestApi } from '../../rest/OrdererRestApi'; import { PeerRestApi } from '../../rest/PeerRestApi'; +import SignatureRestApi from '../../rest/SignatureRestApi'; import Helper from '../../utils/helper'; import NodeStatus from '../../utils/status'; import ConfigOverride from '../ConfigOverride/ConfigOverride'; @@ -41,6 +42,12 @@ const Log = new Logger(SCOPE); class JoinChannelModal extends React.Component { async componentDidMount() { + let channelList = this.props.channelList; + if (!channelList) { + const { channels } = await ChannelApi.getAllChannels(); + this.populatePendingChannels(channels); + channelList = channels; + } const orderers = await OrdererRestApi.getOrderers(true); let channel = this.props.isPending ? this.props.pendingChannelName : this.props.isAddingNode ? this.props.existingChannel : ''; this.props.updateState(SCOPE, { @@ -57,6 +64,7 @@ class JoinChannelModal extends React.Component { addressOverrides: [], channel_warning_20_details: [], channel_warning_20: false, + channelList, }); let orderer = this.props.orderer; if (this.props.isAddingNode && this.props.existingOrderer) { @@ -83,6 +91,131 @@ class JoinChannelModal extends React.Component { } } + + async getCreateChannelRequests() { + let requests = []; + if (this.props.signature_requests && this.props.signature_requests.length) { + this.props.signature_requests.forEach(req => { + if (this.isVisibleCreateRequest(req)) { + requests.push(req); + } + }); + } else { + requests = await SignatureRestApi.getCreateChannelRequests(); + } + return requests; + }; + + populatePendingChannels = joinedChannels => { + OrdererRestApi.getOrderers(false).then(async orderers => { + if (!this.mounted) { + return; + } + + // Build list that includes all raft nodes from all the console ordering services + let all_nodes = []; + orderers.forEach(orderer => { + if (_.has(orderer, 'raft')) { + orderer.raft.forEach(x => all_nodes.push(x)); + } else { + all_nodes.push(orderer); + } + }); + + // Get pending channels from notifications instead of local storage + const pendingChannels = []; + let signature_requests = await this.getCreateChannelRequests(); + signature_requests.forEach(notification => { + let notification_orderers = []; + if (_.has(notification, 'consenters')) { + notification.consenters.forEach(url => { + let orderer_details = all_nodes.find(x => _.toLower(x.backend_addr) === _.toLower(url)); + if (orderer_details) { + notification_orderers.push(orderer_details); + } else { + notification_orderers.push({ backend_addr: url, name: url }); + } + }); + } else { + // If there were pending tiles before migrating to 2.1.3, handle them the old way so that we dont loose the tile after migration + notification.orderers.forEach(url => { + let orderer_details = all_nodes.find(x => { + const url1 = x.url2use.substring(x.url2use.indexOf('/grpcwp/') + 8); // Proxy ports have changed, so compare only url after /grpcwp/ + const url2 = url.indexOf('/grpcwp/') > 0 ? url.substring(url.indexOf('/grpcwp/') + 8) : url; + return _.toLower(decodeURIComponent(url1)) === _.toLower(decodeURIComponent(url2)); + }); + if (orderer_details) { + notification_orderers.push(orderer_details); + } else { + notification_orderers.push({ backend_addr: url, name: url }); + } + }); + } + let matchingJoinedChannel = + joinedChannels && joinedChannels.length + ? joinedChannels.find(channel => { + let allChannelOrderers = []; + if (channel.orderers) { + channel.orderers.forEach(orderer => { + if (_.has(orderer, 'raft')) { + orderer.raft.forEach(y => allChannelOrderers.push(y)); + } else { + allChannelOrderers.push(orderer); + } + }); + } + let joinedChannelOrderers = allChannelOrderers.map(orderer => (orderer.backend_addr ? orderer.backend_addr : orderer.name)); + let pendingChannelOrderers = notification_orderers + ? notification_orderers.map(orderer => (orderer ? (orderer.backend_addr ? orderer.backend_addr : orderer.name) : '')) + : []; + let match = channel.name === notification.channel && _.intersection(pendingChannelOrderers, joinedChannelOrderers).length > 0; + return match; + }) + : null; + if (!matchingJoinedChannel) { + pendingChannels.push({ + id: notification.channel, + name: notification.channel, + orderers: notification_orderers, + pending: true, + }); + } + }); + + let allChannels = _.size(joinedChannels) > 0 ? joinedChannels.concat(pendingChannels) : pendingChannels; + // Filter out the pending channels whose orderers are not imported in this console + let filteredChannels = []; + if (_.size(all_nodes) > 0) { + const all_nodes_grpcurls = all_nodes.map(x => x.grpcwp_url); // To support older notifications that dont have consenters data + const all_nodes_backendaddr = all_nodes.map(x => x.backend_addr); + const all_nodes_url2use = all_nodes.map(x => x.url2use); + const consoleOrdererAddresses = all_nodes_backendaddr.concat(all_nodes_grpcurls).concat(all_nodes_url2use); + + filteredChannels = allChannels.filter(channel => { + let channelOrdererAddresses = channel.orderers.map(x => x.backend_addr); + return channel.pending ? _.intersection(consoleOrdererAddresses, channelOrdererAddresses).length > 0 : channel; + }); + } else { + filteredChannels = allChannels.filter(channel => { + return channel.pending ? false : channel; + }); + } + // Pending tile should show only one associated orderer(which includes all the raft nodes) + pendingChannels.forEach(pc => { + let pc_cluster_ids = pc.orderers.map(x => x.cluster_id); + orderers.forEach(orderer => { + if (pc_cluster_ids.includes(orderer.cluster_id)) { + pc.orderers = [orderer]; + } + }); + }); + + Log.debug('All channels:', allChannels); + Log.debug('Filtered channels:', filteredChannels); + return filteredChannels; + }); + }; + async calculateCapabilityWarning(channel_config, orderer, selectedPeers, channel) { let all_warning_20 = false; let all_warning_20_details = []; @@ -504,8 +637,8 @@ class JoinChannelModal extends React.Component { this.checkPeerMappings(change.selectedPeers); }; - onChannelChange = (change, valid) => { - this.props.updateState(SCOPE, { disableSubmit: !valid }); + onChannelChange = async (change, valid) => { + this.props.updateState(SCOPE, { disableSubmit: !valid, channel: change.selectedChannel.id, existingMembers: change.selectedChannel.peers }); }; toggleAnchorPeer = () => { @@ -721,6 +854,7 @@ class JoinChannelModal extends React.Component { ); } + renderSelectChannel(translate) { if (this.props.hideChannelStep || this.props.isPending) { return; @@ -732,19 +866,19 @@ class JoinChannelModal extends React.Component { headerLink={translate('_JOIN_CHANNEL_LINK', { DOC_PREFIX: this.props.docPrefix })} headerLinkText={translate('find_out_more')} title={translate('select_channel')} - disableSubmit={this.props.disableSubmit} + // disableSubmit={this.props.disableSubmit} + disableSubmit={!this.props.channel} onNext={() => this.filterPeers()} >
@@ -810,6 +944,8 @@ const dataProps = { addressOverrides: PropTypes.array, channel_warning_20: PropTypes.bool, channel_warning_20_details: PropTypes.array, + existingMembers: PropTypes.any, + channelList: PropTypes.array }; JoinChannelModal.propTypes = { @@ -823,6 +959,7 @@ JoinChannelModal.propTypes = { export default connect( state => { let newProps = Helper.mapStateToProps(state[SCOPE], dataProps); + newProps['channelList'] = newProps.channelList ? newProps.channelList : state['channels'] ? state['channels']['filteredChannels'] : null; newProps['CRN'] = state['settings'] ? state['settings']['CRN'] : null; newProps['userInfo'] = state['userInfo'] ? state['userInfo']['loggedInAs'] : null; newProps['configtxlator_url'] = state['settings']['configtxlator_url']; diff --git a/packages/apollo/src/rest/EventsRestApi.js b/packages/apollo/src/rest/EventsRestApi.js index b77d3522..270ba67f 100644 --- a/packages/apollo/src/rest/EventsRestApi.js +++ b/packages/apollo/src/rest/EventsRestApi.js @@ -71,7 +71,7 @@ class EventsRestApi { }).join(', '); EventsRestApi.recordActivity({ status: status === 'error' ? 'error' : 'success', - log: `${peers.length > 1 ? 'peers' : 'peer'} ${peer_names} ${peers.length > 1 ? 'have' : 'has'} ${status === 'error' ? 'failed to ' : ''} joined the channel "${channel_id}"`, + log: `${peers.length > 1 ? 'peers' : 'peer'} ${peer_names} ${peers.length > 1 ? 'have' : 'has'} ${status === 'error' ? 'failed to ' : ''}joined the channel "${channel_id}"`, code: status === 'error' ? 403 : 200 }); } catch (e) { @@ -86,7 +86,7 @@ class EventsRestApi { }).join(', '); EventsRestApi.recordActivity({ status: status === 'error' ? 'error' : 'success', - log: `${peers.length > 1 ? 'peers' : 'peer'} ${peer_names} ${peers.length > 1 ? 'have' : 'has'} ${status === 'error' ? 'failed to ' : ''} disconnect from the channel "${channel_id}"`, + log: `${peers.length > 1 ? 'peers' : 'peer'} ${peer_names} ${peers.length > 1 ? 'have' : 'has'} ${status === 'error' ? 'failed to ' : ''}disconnect from the channel "${channel_id}"`, code: status === 'error' ? 403 : 200 }); } catch (e) { diff --git a/packages/apollo/src/utils/status.js b/packages/apollo/src/utils/status.js index 828dd4ee..2540f2f7 100644 --- a/packages/apollo/src/utils/status.js +++ b/packages/apollo/src/utils/status.js @@ -58,12 +58,10 @@ const NodeStatus = { } } - console.log('ibp99 - getStatusFromPhase', status); return status; }, checkResources(node) { - console.log('ibp99 - checkResources', node.id); return new Promise((resolve, reject) => { NodeRestApi.api_getCurrentNodeDeployer(node) .then(resp => { @@ -85,10 +83,8 @@ const NodeStatus = { }); } else { if ((node.type === 'fabric-orderer' || node.type === 'orderer') && node.consenter_proposal_fin === false) { - console.log('ibp99 - getting comp status from deployer', node.id); NodeRestApi.getNodeDetailsFromDeployer(node.id) .then(() => { - console.log('ibp99 - deployer says the component is running', node.id); resolve({ id: node.id, status: 'running', @@ -266,7 +262,6 @@ const NodeStatus = { // all good, so return status } if (status) { - console.log('ibp99 - getStatusInternal 1', id, status); this.updateStatus(id, status, scope, prop, callback); complete[id] = true; } @@ -284,7 +279,6 @@ const NodeStatus = { if (this.in_progress[id]) { results_list.forEach(result => { if (result && result.id) { - console.log('ibp99 - getStatusInternal 2', result.id, result.status); this.updateStatus(result.id, result.status, scope, prop, callback); switch (result.status) { case 'initialized':