Skip to content
This repository was archived by the owner on May 17, 2021. It is now read-only.

Commit 7f7e891

Browse files
authored
feat: Add cancel connection attempt COMPASS-4393 (#257)
1 parent e9da47e commit 7f7e891

23 files changed

+2838
-271
lines changed

.github/workflows/run-tests.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ jobs:
1010
name: Check and Test
1111
runs-on: ubuntu-20.04
1212

13+
services:
14+
mongodb:
15+
image: mongo:4.2.3
16+
ports:
17+
- 27018:27017
18+
1319
steps:
1420
- uses: actions/checkout@v2
1521
- uses: actions/setup-node@v1

package-lock.json

Lines changed: 1704 additions & 117 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
"prestart": "electron-rebuild --force --only keytar",
1717
"start": "cross-env NODE_ENV=development webpack-dev-server --config ./config/webpack.dev.config.js",
1818
"start:watch": "npm run clean && webpack --config ./config/webpack.watch.config.js",
19+
"pretest": "cross-env MONGODB_VERSION=4.2.3 mongodb-runner start --port=27018",
20+
"posttest": "mongodb-runner stop --port=27018",
1921
"test": "npm run test:mocha && npm run test:karma",
2022
"test:watch": "cross-env NODE_ENV=test mocha-webpack \"./src/**/*.spec.js\" --watch",
2123
"test:karma": "npm run prestart && cross-env NODE_ENV=test karma start",
@@ -109,6 +111,7 @@
109111
"mongodb-connection-model": "^19.0.2",
110112
"mongodb-data-service": "^18.2.1",
111113
"mongodb-js-precommit": "^2.0.0",
114+
"mongodb-runner": "^4.8.1",
112115
"mongodb-shell-to-url": "^0.1.0",
113116
"node-loader": "^0.6.0",
114117
"nyc": "^15.0.0",
@@ -140,6 +143,8 @@
140143
"webpack-sources": "1.4.3"
141144
},
142145
"dependencies": {
146+
"@leafygreen-ui/button": "^10.0.1",
147+
"@leafygreen-ui/typography": "^7.3.2",
143148
"lodash": "^4.17.15"
144149
}
145150
}

src/actions/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const Actions = Reflux.createActions({
77
validateConnectionString: { sync: true },
88
onAuthSourceChanged: { sync: true },
99
onAuthStrategyChanged: { sync: true },
10+
onCancelConnectionAttemptClicked: { sync: true },
1011
onChangeViewClicked: { sync: true },
1112
onConnectionFormChanged: { sync: true },
1213
onConnectClicked: { sync: true },

src/assets/svg/connecting-illustration.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/connect.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@ import ConnectionString from './form/connection-string';
1010
import Help from './form/help';
1111
import IsFavoritePill from './form/is-favorite-pill';
1212
import ConfirmEditConnectionString from './modal/confirm-edit-connection-string';
13-
13+
import Connecting from './modal/connecting';
1414
import {
1515
CONNECTION_FORM_VIEW,
1616
CONNECTION_STRING_VIEW
1717
} from '../constants/connection-views';
18-
1918
import styles from './connect.less';
2019

2120
class Connect extends React.Component {
2221
static displayName = 'Connect';
2322

2423
static propTypes = {
25-
currentConnection: PropTypes.object,
24+
connectingStatusText: PropTypes.string,
2625
connections: PropTypes.object,
26+
currentConnection: PropTypes.object,
27+
currentConnectionAttempt: PropTypes.object,
28+
isConnected: PropTypes.bool,
2729
viewType: PropTypes.string,
2830
isModalVisible: PropTypes.bool,
2931
isMessageVisible: PropTypes.bool,
@@ -149,6 +151,10 @@ class Connect extends React.Component {
149151
</div>
150152
<Help {...this.props} />
151153
</div>
154+
<Connecting
155+
connectingStatusText={this.props.connectingStatusText}
156+
currentConnectionAttempt={this.props.currentConnectionAttempt}
157+
/>
152158
<ConfirmEditConnectionString
153159
isEditURIConfirm={this.props.isEditURIConfirm}
154160
/>

src/components/connect.less

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@import './sidebar/sidebar.less';
22

33
@compass-sidebar-secondary-text-color: @gray6;
4-
@compass-sidebar-atlas-background-color: @gray1;
54
@compass-sidebar-atlas-background-color: lighten(hsl(204, 29%, 18%), 5%);
65

76
.page {
@@ -508,15 +507,30 @@ label {
508507

509508
.buttons {
510509
margin: 0 25px 10px;
511-
overflow: auto;
512510
display: flex;
513511
justify-content: flex-end;
514512

515-
button {
513+
.button {
516514
margin-left: 5px;
517515
}
518516
}
519517

518+
.btn-loading {
519+
border: 2px solid transparent;
520+
border-top: 2px solid @green2;
521+
border-radius: 50%;
522+
padding: 0;
523+
margin: 0;
524+
box-sizing: border-box;
525+
width: 14px;
526+
height: 14px;
527+
background: none;
528+
outline: none;
529+
margin-right: 5px;
530+
531+
animation: connect-btn-loader-spin 500ms linear infinite;
532+
}
533+
520534
.disabled-uri {
521535
background-color: #e9eeec !important;
522536
box-shadow: none !important;
@@ -621,6 +635,90 @@ label {
621635
}
622636
}
623637

638+
.connecting-modal-backdrop {
639+
background-color: transparent !important;
640+
}
641+
642+
.connecting-background {
643+
position: fixed;
644+
z-index: 500;
645+
top: 0;
646+
left: 0;
647+
bottom: 0;
648+
right: 0;
649+
650+
.connecting-background-gradient {
651+
opacity: 0.9;
652+
animation: opacityFadeIn 0.2s ease-out;
653+
}
654+
}
655+
656+
@keyframes opacityFadeIn {
657+
0% {
658+
opacity: 0;
659+
}
660+
661+
100% {
662+
opacity: 0.9;
663+
}
664+
}
665+
666+
.connecting-modal-content {
667+
text-align: center;
668+
padding: 24px;
669+
670+
.connecting-modal-status {
671+
margin-top: 24px;
672+
font-weight: bold;
673+
}
674+
675+
.connecting-modal-animation {
676+
margin-top: 24px;
677+
text-align: center;
678+
679+
.connecting-compass-animation-svg {
680+
width: 70px;
681+
height: auto;
682+
}
683+
684+
.connecting-compass-shadow {
685+
fill:#136149;
686+
opacity:0.12;
687+
}
688+
.connecting-compass-shadow-stroke {
689+
stroke:#136149;
690+
stroke-linecap:round;
691+
stroke-linejoin:round;
692+
fill: none;
693+
opacity:0.12;
694+
}
695+
696+
.connecting-compass-circle-1 {
697+
fill:none;
698+
stroke:#136149;
699+
stroke-linecap:round;
700+
stroke-linejoin:round;
701+
}
702+
.connecting-compass-circle-2 {
703+
fill:#f7a76f;
704+
}
705+
.connecting-compass-circle-3 {
706+
fill:#fef7e3;
707+
opacity:0.85;
708+
}
709+
.connecting-compass-arrow-1 {
710+
fill:#f9d3c5;
711+
}
712+
.connecting-compass-arrow-2 {
713+
fill:#09804c;
714+
}
715+
}
716+
717+
.connecting-modal-cancel-btn {
718+
margin-top: 24px;
719+
}
720+
}
721+
624722
.connect-sidebar-connections::-webkit-scrollbar-track {
625723
background-color: rgba(0, 0, 0, 0.12);
626724
border-bottom-left-radius: 3px;
@@ -710,6 +808,10 @@ label {
710808
}
711809
}
712810

811+
.confirm-edit-modal-button {
812+
margin-left: 5px;
813+
}
814+
713815
.favorite-modal {
714816
width: 500px;
715817
padding-left: 40px;
@@ -887,3 +989,8 @@ label {
887989
0 0 4px rgba(88, 151, 251, 1);
888990
}
889991
}
992+
993+
@keyframes connect-btn-loader-spin {
994+
0% { transform: rotate(0deg); }
995+
100% { transform: rotate(360deg); }
996+
}

src/components/form/connection-form.jsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ConnectionForm extends React.Component {
2121

2222
static propTypes = {
2323
currentConnection: PropTypes.object.isRequired,
24+
currentConnectionAttempt: PropTypes.object,
2425
isValid: PropTypes.bool.isRequired,
2526
isHostChanged: PropTypes.bool,
2627
isPortChanged: PropTypes.bool
@@ -121,7 +122,10 @@ class ConnectionForm extends React.Component {
121122
hostname={this.props.currentConnection.hostname}
122123
isHostChanged={this.props.isHostChanged} />
123124
{this.renderPort()}
124-
<SRVInput isSrvRecord={this.props.currentConnection.isSrvRecord} />
125+
<SRVInput
126+
currentConnectionAttempt={this.props.currentConnectionAttempt}
127+
isSrvRecord={this.props.currentConnection.isSrvRecord}
128+
/>
125129
</FormGroup>
126130
<Authentication
127131
currentConnection={this.props.currentConnection}
@@ -157,13 +161,16 @@ class ConnectionForm extends React.Component {
157161
return (
158162
<form
159163
onChange={this.onConnectionFormChanged.bind(this)}
160-
className={classnames(styles['connect-form'])} >
161-
<div className={classnames(styles.tabs)}>
162-
<div className={classnames(styles['tabs-container'])}>
163-
{this.renderTabs()}
164-
{this.renderView()}
164+
className={classnames(styles['connect-form'])}
165+
>
166+
<fieldset disabled={!!this.props.currentConnectionAttempt}>
167+
<div className={classnames(styles.tabs)}>
168+
<div className={classnames(styles['tabs-container'])}>
169+
{this.renderTabs()}
170+
{this.renderView()}
171+
</div>
165172
</div>
166-
</div>
173+
</fieldset>
167174
<FormActions {...this.props } />
168175
</form>
169176
);

src/components/form/connection-form.spec.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,50 @@ describe('ConnectionForm [Component]', () => {
8484
expect(authentication.prop('currentConnection')).to.deep.equal(connection);
8585
expect(authentication.prop('isValid')).to.equal(true);
8686
});
87+
88+
it('has the form fieldset enabled', () => {
89+
expect(component.find('fieldset[disabled=true]')).to.be.not.present();
90+
expect(component.find('fieldset[disabled=false]')).to.be.present();
91+
});
92+
});
93+
94+
context('when it is currently connecting', () => {
95+
const appRegistry = new AppRegistry();
96+
const AUTH_ROLE = {
97+
name: 'MONGODB',
98+
component: TestComponent,
99+
selectOption: { 'MONGODB': 'Username / Password' }
100+
};
101+
102+
before(() => {
103+
global.hadronApp = hadronApp;
104+
global.hadronApp.appRegistry = appRegistry;
105+
global.hadronApp.appRegistry.registerRole('Connect.AuthStrategy', AUTH_ROLE);
106+
});
107+
108+
after(() => {
109+
global.hadronApp.appRegistry.deregisterRole('Connect.AuthStrategy', AUTH_ROLE);
110+
});
111+
112+
it('disables the form', () => {
113+
const component = mount(
114+
<ConnectionForm
115+
currentConnectionAttempt
116+
currentConnection={{
117+
authStrategy: 'MONGODB',
118+
isSrvRecord: false,
119+
readPreference: 'primaryPreferred',
120+
attributes: { hostname: 'localhost' }
121+
}}
122+
isHostChanged={false}
123+
isPortChanged={false}
124+
isValid
125+
/>
126+
);
127+
128+
expect(component.find('fieldset[disabled=true]')).to.be.present();
129+
expect(component.find('fieldset[disabled=false]')).to.not.be.present();
130+
});
87131
});
88132

89133
context('when SRV input was toggled', () => {

src/components/form/connection-string.jsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ConnectionString extends React.Component {
1616
customUrl: PropTypes.string,
1717
isValid: PropTypes.bool,
1818
isConnected: PropTypes.bool,
19+
currentConnectionAttempt: PropTypes.object,
1920
errorMessage: PropTypes.string,
2021
syntaxErrorMessage: PropTypes.string,
2122
hasUnsavedChanges: PropTypes.bool,
@@ -30,23 +31,26 @@ class ConnectionString extends React.Component {
3031
data-test-id="connect-string"
3132
className={classnames(styles['connect-string'])}
3233
>
33-
<FormGroup separator>
34-
<ConnectionStringInput
35-
customUrl={this.props.customUrl}
34+
<fieldset disabled={!!this.props.currentConnectionAttempt}>
35+
<FormGroup separator>
36+
<ConnectionStringInput
37+
customUrl={this.props.customUrl}
38+
isURIEditable={this.props.isURIEditable}
39+
/>
40+
</FormGroup>
41+
<FormActions
42+
currentConnection={this.props.currentConnection}
43+
isValid={this.props.isValid}
44+
isConnected={this.props.isConnected}
45+
currentConnectionAttempt={this.props.currentConnectionAttempt}
46+
errorMessage={this.props.errorMessage}
47+
syntaxErrorMessage={this.props.syntaxErrorMessage}
48+
hasUnsavedChanges={this.props.hasUnsavedChanges}
49+
viewType={this.props.viewType}
3650
isURIEditable={this.props.isURIEditable}
51+
isSavedConnection={this.props.isSavedConnection}
3752
/>
38-
</FormGroup>
39-
<FormActions
40-
currentConnection={this.props.currentConnection}
41-
isValid={this.props.isValid}
42-
isConnected={this.props.isConnected}
43-
errorMessage={this.props.errorMessage}
44-
syntaxErrorMessage={this.props.syntaxErrorMessage}
45-
hasUnsavedChanges={this.props.hasUnsavedChanges}
46-
viewType={this.props.viewType}
47-
isURIEditable={this.props.isURIEditable}
48-
isSavedConnection={this.props.isSavedConnection}
49-
/>
53+
</fieldset>
5054
</form>
5155
);
5256
}

0 commit comments

Comments
 (0)