Просмотр исходного кода

Merge pull request #413 from smiclea/promise-to-await

Refactor all JS promises to async / await
Dorin Paslaru 6 лет назад
Родитель
Сommit
b9d3c92f8b
43 измененных файлов с 1648 добавлено и 1529 удалено
  1. 3 4
      src/components/App.jsx
  2. 1 1
      src/components/molecules/ProjectListItem/ProjectListItem.jsx
  3. 3 4
      src/components/organisms/DetailsPageHeader/DetailsPageHeader.jsx
  4. 46 38
      src/components/organisms/EditReplica/EditReplica.jsx
  5. 15 17
      src/components/organisms/Endpoint/Endpoint.jsx
  6. 22 26
      src/components/organisms/PageHeader/PageHeader.jsx
  7. 12 4
      src/components/pages/AssessmentDetailsPage/AssessmentDetailsPage.jsx
  8. 25 25
      src/components/pages/EndpointDetailsPage/EndpointDetailsPage.jsx
  9. 11 12
      src/components/pages/EndpointsPage/EndpointsPage.jsx
  10. 33 33
      src/components/pages/MigrationDetailsPage/MigrationDetailsPage.jsx
  11. 3 7
      src/components/pages/MigrationsPage/MigrationsPage.jsx
  12. 40 48
      src/components/pages/ProjectDetailsPage/ProjectDetailsPage.jsx
  13. 7 9
      src/components/pages/ProjectsPage/ProjectsPage.jsx
  14. 49 50
      src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.jsx
  15. 18 20
      src/components/pages/ReplicasPage/ReplicasPage.jsx
  16. 7 9
      src/components/pages/UserDetailsPage/UserDetailsPage.jsx
  17. 3 4
      src/components/pages/UsersPage/UsersPage.jsx
  18. 88 68
      src/components/pages/WizardPage/WizardPage.jsx
  19. 119 118
      src/sources/EndpointSource.js
  20. 11 14
      src/sources/InstanceSource.js
  21. 27 25
      src/sources/MigrationSource.js
  22. 6 7
      src/sources/NetworkSource.js
  23. 38 38
      src/sources/NotificationSource.js
  24. 52 58
      src/sources/ProjectSource.js
  25. 21 29
      src/sources/ProviderSource.js
  26. 44 43
      src/sources/ReplicaSource.js
  27. 40 38
      src/sources/ScheduleSource.js
  28. 124 140
      src/sources/UserSource.js
  29. 17 13
      src/sources/WizardSource.js
  30. 131 90
      src/stores/EndpointStore.js
  31. 92 67
      src/stores/InstanceStore.js
  32. 48 37
      src/stores/MigrationStore.js
  33. 14 12
      src/stores/NetworkStore.js
  34. 4 7
      src/stores/NotificationStore.js
  35. 74 60
      src/stores/ProjectStore.js
  36. 122 105
      src/stores/ProviderStore.js
  37. 95 76
      src/stores/ReplicaStore.js
  38. 33 35
      src/stores/ScheduleStore.js
  39. 121 111
      src/stores/UserStore.js
  40. 18 17
      src/stores/WizardStore.js
  41. 1 0
      src/types/User.js
  42. 3 4
      src/utils/Config.js
  43. 7 6
      src/utils/ObjectUtils.js

+ 3 - 4
src/components/App.jsx

@@ -74,11 +74,10 @@ class App extends React.Component<{}, State> {
     isConfigReady: false,
     isConfigReady: false,
   }
   }
 
 
-  componentWillMount() {
+  async componentWillMount() {
     userStore.tokenLogin()
     userStore.tokenLogin()
-    configLoader.load().then(() => {
-      this.setState({ isConfigReady: true })
-    })
+    await configLoader.load()
+    this.setState({ isConfigReady: true })
   }
   }
 
 
   render() {
   render() {

+ 1 - 1
src/components/molecules/ProjectListItem/ProjectListItem.jsx

@@ -97,7 +97,7 @@ type Props = {
   onClick: () => void,
   onClick: () => void,
   getMembers: (projectId: string) => number,
   getMembers: (projectId: string) => number,
   isCurrentProject: (projectId: string) => boolean,
   isCurrentProject: (projectId: string) => boolean,
-  onSwitchProjectClick: (projectId: string) => void,
+  onSwitchProjectClick: (projectId: string) => void | Promise<void>,
 }
 }
 const testName = 'plItem'
 const testName = 'plItem'
 @observer
 @observer

+ 3 - 4
src/components/organisms/DetailsPageHeader/DetailsPageHeader.jsx

@@ -101,14 +101,13 @@ class DetailsPageHeader extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
-  pollData() {
+  async pollData() {
     if (this.stopPolling) {
     if (this.stopPolling) {
       return
       return
     }
     }
 
 
-    notificationStore.loadData().then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, 5000)
-    })
+    await notificationStore.loadData()
+    this.pollTimeout = setTimeout(() => { this.pollData() }, 5000)
   }
   }
 
 
   render() {
   render() {

+ 46 - 38
src/components/organisms/EditReplica/EditReplica.jsx

@@ -110,31 +110,38 @@ class EditReplica extends React.Component<Props, State> {
     this.setState({ selectedPanel: this.hasSourceOptions() ? 'source_options' : 'dest_options' })
     this.setState({ selectedPanel: this.hasSourceOptions() ? 'source_options' : 'dest_options' })
   }
   }
 
 
-  loadData(useCache: boolean) {
-    providerStore.loadProviders().then(() => {
-      if (this.hasStorageMap()) {
-        endpointStore.loadStorage(this.props.destinationEndpoint.id, {})
-      }
-      providerStore.loadDestinationSchema(this.props.destinationEndpoint.type, this.props.type || 'replica', useCache)
-        .then(() => providerStore.getOptionsValues({
-          optionsType: 'destination',
-          endpointId: this.props.destinationEndpoint.id,
-          provider: this.props.destinationEndpoint.type,
-          useCache,
-        })).then(() => {
-          this.loadEnvDestinationOptions()
-        })
+  async loadData(useCache: boolean) {
+    await providerStore.loadProviders()
 
 
-      if (!this.hasSourceOptions()) {
-        return
-      }
-      providerStore.loadSourceSchema(this.props.sourceEndpoint.type, this.props.type || 'replica', useCache)
-        .then(() => providerStore.getOptionsValues({
-          optionsType: 'source',
-          endpointId: this.props.sourceEndpoint.id,
-          provider: this.props.sourceEndpoint.type,
-          useCache,
-        }))
+    if (this.hasStorageMap()) {
+      endpointStore.loadStorage(this.props.destinationEndpoint.id, {})
+    }
+
+    this.loadDestinationOptions(useCache)
+
+    if (!this.hasSourceOptions()) {
+      return
+    }
+    this.loadOptions(this.props.sourceEndpoint, 'source', useCache)
+  }
+
+  async loadDestinationOptions(useCache: boolean) {
+    await this.loadOptions(this.props.destinationEndpoint, 'destination', useCache)
+    this.loadEnvDestinationOptions()
+  }
+
+  async loadOptions(endpoint: Endpoint, optionsType: 'source' | 'destination', useCache: boolean) {
+    await providerStore.loadOptionsSchema({
+      providerName: endpoint.type,
+      schemaType: this.props.type || 'replica',
+      optionsType,
+      useCache,
+    })
+    await providerStore.getOptionsValues({
+      optionsType,
+      endpointId: endpoint.id,
+      providerName: endpoint.type,
+      useCache,
     })
     })
   }
   }
 
 
@@ -182,7 +189,7 @@ class EditReplica extends React.Component<Props, State> {
 
 
   loadEnvDestinationOptions(field?: Field) {
   loadEnvDestinationOptions(field?: Field) {
     let envData = getFieldChangeOptions({
     let envData = getFieldChangeOptions({
-      provider: this.props.destinationEndpoint.type,
+      providerName: this.props.destinationEndpoint.type,
       schema: providerStore.destinationSchema,
       schema: providerStore.destinationSchema,
       data: {
       data: {
         ...this.parseReplicaData(this.props.replica.destination_environment),
         ...this.parseReplicaData(this.props.replica.destination_environment),
@@ -196,7 +203,7 @@ class EditReplica extends React.Component<Props, State> {
       providerStore.getOptionsValues({
       providerStore.getOptionsValues({
         optionsType: 'destination',
         optionsType: 'destination',
         endpointId: this.props.destinationEndpoint.id,
         endpointId: this.props.destinationEndpoint.id,
-        provider: this.props.destinationEndpoint.type,
+        providerName: this.props.destinationEndpoint.type,
         useCache: true,
         useCache: true,
         envData,
         envData,
       })
       })
@@ -252,7 +259,7 @@ class EditReplica extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
-  handleUpdateClick() {
+  async handleUpdateClick() {
     this.setState({ updateDisabled: true })
     this.setState({ updateDisabled: true })
 
 
     let updateData: UpdateData = {
     let updateData: UpdateData = {
@@ -263,21 +270,22 @@ class EditReplica extends React.Component<Props, State> {
     }
     }
     if (this.props.type === 'replica') {
     if (this.props.type === 'replica') {
       let storageConfigDefault = this.getFieldValue('destination', 'default_storage') || endpointStore.storageConfigDefault
       let storageConfigDefault = this.getFieldValue('destination', 'default_storage') || endpointStore.storageConfigDefault
-      replicaStore.update(this.props.replica, this.props.destinationEndpoint, updateData, storageConfigDefault).then(() => {
+      try {
+        await replicaStore.update(this.props.replica, this.props.destinationEndpoint, updateData, storageConfigDefault)
         this.props.onRequestClose()
         this.props.onRequestClose()
         this.props.onUpdateComplete(`/replica/executions/${this.props.replica.id}`)
         this.props.onUpdateComplete(`/replica/executions/${this.props.replica.id}`)
-      }).catch(() => {
+      } catch (err) {
         this.setState({ updateDisabled: false })
         this.setState({ updateDisabled: false })
-      })
+      }
     } else {
     } else {
-      migrationStore.recreate(this.props.replica, this.props.sourceEndpoint, this.props.destinationEndpoint, updateData)
-        .then((migration: MainItem) => {
-          migrationStore.clearDetails()
-          this.props.onRequestClose()
-          this.props.onUpdateComplete(`/migration/tasks/${migration.id}`)
-        }).catch(() => {
-          this.setState({ updateDisabled: false })
-        })
+      try {
+        let migration: MainItem = await migrationStore.recreate(this.props.replica, this.props.sourceEndpoint, this.props.destinationEndpoint, updateData)
+        migrationStore.clearDetails()
+        this.props.onRequestClose()
+        this.props.onUpdateComplete(`/migration/tasks/${migration.id}`)
+      } catch (err) {
+        this.setState({ updateDisabled: false })
+      }
     }
     }
   }
   }
 
 

+ 15 - 17
src/components/organisms/Endpoint/Endpoint.jsx

@@ -276,34 +276,32 @@ class Endpoint extends React.Component<Props, State> {
     return invalidFields.length > 0
     return invalidFields.length > 0
   }
   }
 
 
-  update() {
+  async update() {
     if (!this.state.endpoint) {
     if (!this.state.endpoint) {
       return
       return
     }
     }
 
 
-    endpointStore.update(this.state.endpoint).then(() => {
-      let endpoint = endpointStore.endpoints.find(e => this.state.endpoint && e.id === this.state.endpoint.id)
-      if (!endpoint) {
-        throw new Error('endpoint not found')
-      }
+    await endpointStore.update(this.state.endpoint)
+    let endpoint = endpointStore.endpoints.find(e => this.state.endpoint && e.id === this.state.endpoint.id)
+    if (!endpoint) {
+      throw new Error('endpoint not found')
+    }
 
 
-      this.setState({ endpoint: ObjectUtils.flatten(endpoint) })
-      notificationStore.alert('Validating endpoint ...')
-      endpointStore.validate(endpoint)
-    })
+    this.setState({ endpoint: ObjectUtils.flatten(endpoint) })
+    notificationStore.alert('Validating endpoint ...')
+    endpointStore.validate(endpoint)
   }
   }
 
 
-  add() {
+  async add() {
     if (!this.state.endpoint) {
     if (!this.state.endpoint) {
       return
       return
     }
     }
 
 
-    endpointStore.add(this.state.endpoint).then(() => {
-      let endpoint = endpointStore.endpoints[0]
-      this.setState({ isNew: false, endpoint: ObjectUtils.flatten(endpoint) })
-      notificationStore.alert('Validating endpoint ...')
-      endpointStore.validate(endpoint)
-    })
+    await endpointStore.add(this.state.endpoint)
+    let endpoint = endpointStore.endpoints[0]
+    this.setState({ isNew: false, endpoint: ObjectUtils.flatten(endpoint) })
+    notificationStore.alert('Validating endpoint ...')
+    endpointStore.validate(endpoint)
   }
   }
 
 
   renderEndpointStatus() {
   renderEndpointStatus() {

+ 22 - 26
src/components/organisms/PageHeader/PageHeader.jsx

@@ -179,15 +179,14 @@ class PageHeader extends React.Component<Props, State> {
     this.setState({ showChooseProviderModal: !options || !options.autoClose, showEndpointModal: false })
     this.setState({ showChooseProviderModal: !options || !options.autoClose, showEndpointModal: false })
   }
   }
 
 
-  handleProjectChange(project: Project) {
-    userStore.switchProject(project.id).then(() => {
-      projectStore.getProjects()
-      notificationStore.loadData()
+  async handleProjectChange(project: Project) {
+    await userStore.switchProject(project.id)
+    projectStore.getProjects()
+    notificationStore.loadData()
 
 
-      if (this.props.onProjectChange) {
-        this.props.onProjectChange(project)
-      }
-    })
+    if (this.props.onProjectChange) {
+      this.props.onProjectChange(project)
+    }
   }
   }
 
 
   handleUserModalClose() {
   handleUserModalClose() {
@@ -197,13 +196,12 @@ class PageHeader extends React.Component<Props, State> {
     this.setState({ showUserModal: false })
     this.setState({ showUserModal: false })
   }
   }
 
 
-  handleUserUpdateClick(user: User) {
-    userStore.add(user).then(() => {
-      if (this.props.onModalClose) {
-        this.props.onModalClose()
-      }
-      this.setState({ showUserModal: false })
-    })
+  async handleUserUpdateClick(user: User) {
+    await userStore.add(user)
+    if (this.props.onModalClose) {
+      this.props.onModalClose()
+    }
+    this.setState({ showUserModal: false })
   }
   }
 
 
   handleProjectModalClose() {
   handleProjectModalClose() {
@@ -213,16 +211,15 @@ class PageHeader extends React.Component<Props, State> {
     this.setState({ showProjectModal: false })
     this.setState({ showProjectModal: false })
   }
   }
 
 
-  handleProjectModalUpdateClick(project: Project) {
-    projectStore.add(project).then(() => {
-      if (this.props.onModalClose) {
-        this.props.onModalClose()
-      }
-      this.setState({ showProjectModal: false })
-    })
+  async handleProjectModalUpdateClick(project: Project) {
+    await projectStore.add(project)
+    if (this.props.onModalClose) {
+      this.props.onModalClose()
+    }
+    this.setState({ showProjectModal: false })
   }
   }
 
 
-  pollData() {
+  async pollData() {
     if (
     if (
       this.stopPolling ||
       this.stopPolling ||
       this.state.showChooseProviderModal ||
       this.state.showChooseProviderModal ||
@@ -234,9 +231,8 @@ class PageHeader extends React.Component<Props, State> {
       return
       return
     }
     }
 
 
-    notificationStore.loadData().then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, 5000)
-    })
+    await notificationStore.loadData()
+    this.pollTimeout = setTimeout(() => { this.pollData() }, 5000)
   }
   }
 
 
   render() {
   render() {

+ 12 - 4
src/components/pages/AssessmentDetailsPage/AssessmentDetailsPage.jsx

@@ -243,9 +243,17 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
 
 
   handleMigrateClick() {
   handleMigrateClick() {
     let endpointType = this.getLocalData().endpoint.type
     let endpointType = this.getLocalData().endpoint.type
-    providerStore.loadDestinationSchema(endpointType, 'replica').then(() => {
+    providerStore.loadOptionsSchema({
+      providerName: endpointType,
+      schemaType: 'replica',
+      optionsType: 'destination',
+    }).then(() => {
       this.setState({ replicaSchema: providerStore.destinationSchema })
       this.setState({ replicaSchema: providerStore.destinationSchema })
-      return providerStore.loadDestinationSchema(endpointType, 'migration')
+      return providerStore.loadOptionsSchema({
+        providerName: endpointType,
+        schemaType: 'migration',
+        optionsType: 'destination',
+      })
     }).then(() => {
     }).then(() => {
       this.setState({ migrationSchema: providerStore.destinationSchema })
       this.setState({ migrationSchema: providerStore.destinationSchema })
     })
     })
@@ -317,7 +325,7 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
     return providerStore.getOptionsValues({
     return providerStore.getOptionsValues({
       optionsType: 'destination',
       optionsType: 'destination',
       endpointId: localData.endpoint.id,
       endpointId: localData.endpoint.id,
-      provider: localData.endpoint.type,
+      providerName: localData.endpoint.type,
     }).then(options => {
     }).then(options => {
       let locations = options.find(o => o.name === 'location')
       let locations = options.find(o => o.name === 'location')
       if (locations && locations.values) {
       if (locations && locations.values) {
@@ -345,7 +353,7 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
     providerStore.getOptionsValues({
     providerStore.getOptionsValues({
       optionsType: 'destination',
       optionsType: 'destination',
       endpointId: localData.endpoint.id,
       endpointId: localData.endpoint.id,
-      provider: localData.endpoint.type,
+      providerName: localData.endpoint.type,
       envData: {
       envData: {
         location: localData.locationName,
         location: localData.locationName,
         resource_group: localData.resourceGroupName,
         resource_group: localData.resourceGroupName,

+ 25 - 25
src/components/pages/EndpointDetailsPage/EndpointDetailsPage.jsx

@@ -103,18 +103,17 @@ class EndpointDetailsPage extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
-  handleDeleteEndpointClick() {
+  async handleDeleteEndpointClick() {
     this.setState({ showEndpointInUseLoadingModal: true })
     this.setState({ showEndpointInUseLoadingModal: true })
 
 
-    Promise.all([replicaStore.getReplicas(), migrationStore.getMigrations()]).then(() => {
-      const endpointUsage = this.getEndpointUsage()
+    await Promise.all([replicaStore.getReplicas(), migrationStore.getMigrations()])
+    const endpointUsage = this.getEndpointUsage()
 
 
-      if (endpointUsage.migrations.length === 0 && endpointUsage.replicas.length === 0) {
-        this.setState({ showDeleteEndpointConfirmation: true, showEndpointInUseLoadingModal: false })
-      } else {
-        this.setState({ showEndpointInUseModal: true, showEndpointInUseLoadingModal: false })
-      }
-    })
+    if (endpointUsage.migrations.length === 0 && endpointUsage.replicas.length === 0) {
+      this.setState({ showDeleteEndpointConfirmation: true, showEndpointInUseLoadingModal: false })
+    } else {
+      this.setState({ showEndpointInUseModal: true, showEndpointInUseLoadingModal: false })
+    }
   }
   }
 
 
   handleDeleteEndpointConfirmation() {
   handleDeleteEndpointConfirmation() {
@@ -170,7 +169,7 @@ class EndpointDetailsPage extends React.Component<Props, State> {
     this.setState({ showDuplicateModal: true })
     this.setState({ showDuplicateModal: true })
   }
   }
 
 
-  handleDuplicate(projectId: string) {
+  async handleDuplicate(projectId: string) {
     let endpoint = this.getEndpoint()
     let endpoint = this.getEndpoint()
     if (!endpoint) {
     if (!endpoint) {
       return
       return
@@ -180,31 +179,32 @@ class EndpointDetailsPage extends React.Component<Props, State> {
 
 
     let shouldSwitchProject = projectId !== (userStore.loggedUser ? userStore.loggedUser.project.id : '')
     let shouldSwitchProject = projectId !== (userStore.loggedUser ? userStore.loggedUser.project.id : '')
 
 
-    endpointStore.duplicate({
+    await endpointStore.duplicate({
       shouldSwitchProject,
       shouldSwitchProject,
       endpoints: [endpoint],
       endpoints: [endpoint],
       onSwitchProject: () => userStore.switchProject(projectId),
       onSwitchProject: () => userStore.switchProject(projectId),
-    }).then(() => {
-      this.props.history.push('/endpoints')
     })
     })
+    this.props.history.push('/endpoints')
   }
   }
 
 
-  loadData() {
+  async loadData() {
     projectStore.getProjects()
     projectStore.getProjects()
 
 
-    endpointStore.getEndpoints().then(() => {
-      let endpoint = this.getEndpoint()
+    this.loadEndpoints()
 
 
-      if (endpoint && endpoint.connection_info && endpoint.connection_info.secret_ref) {
-        endpointStore.getConnectionInfo(endpoint)
-      } else if (endpoint && endpoint.connection_info) {
-        endpointStore.setConnectionInfo(endpoint.connection_info)
-      }
-    })
+    await Promise.all([replicaStore.getReplicas(), migrationStore.getMigrations()])
+    this.setState({ endpointUsage: this.getEndpointUsage() })
+  }
 
 
-    Promise.all([replicaStore.getReplicas(), migrationStore.getMigrations()]).then(() => {
-      this.setState({ endpointUsage: this.getEndpointUsage() })
-    })
+  async loadEndpoints() {
+    await endpointStore.getEndpoints()
+    let endpoint = this.getEndpoint()
+
+    if (endpoint && endpoint.connection_info && endpoint.connection_info.secret_ref) {
+      endpointStore.getConnectionInfo(endpoint)
+    } else if (endpoint && endpoint.connection_info) {
+      endpointStore.setConnectionInfo(endpoint.connection_info)
+    }
   }
   }
 
 
   render() {
   render() {

+ 11 - 12
src/components/pages/EndpointsPage/EndpointsPage.jsx

@@ -124,22 +124,22 @@ class EndpointsPage extends React.Component<{ history: any }, State> {
     this.props.history.push(`/endpoint/${item.id}`)
     this.props.history.push(`/endpoint/${item.id}`)
   }
   }
 
 
-  duplicate(projectId: string) {
+  async duplicate(projectId: string) {
     this.setState({ modalIsOpen: false, duplicating: true })
     this.setState({ modalIsOpen: false, duplicating: true })
 
 
     let shouldSwitchProject = projectId !== (userStore.loggedUser ? userStore.loggedUser.project.id : '')
     let shouldSwitchProject = projectId !== (userStore.loggedUser ? userStore.loggedUser.project.id : '')
     let endpoints = endpointStore.endpoints.filter(e => this.state.selectedEndpoints.find(se => se.id === e.id))
     let endpoints = endpointStore.endpoints.filter(e => this.state.selectedEndpoints.find(se => se.id === e.id))
 
 
-    endpointStore.duplicate({
+    await endpointStore.duplicate({
       shouldSwitchProject,
       shouldSwitchProject,
       endpoints,
       endpoints,
-      onSwitchProject: () => userStore.switchProject(projectId).then(() => {
+      onSwitchProject: async () => {
+        await userStore.switchProject(projectId)
         this.handleProjectChange()
         this.handleProjectChange()
-      }),
-    }).then(() => {
-      this.pollData(true)
-      this.setState({ showDuplicateModal: false, duplicating: false })
+      },
     })
     })
+    this.pollData(true)
+    this.setState({ showDuplicateModal: false, duplicating: false })
   }
   }
 
 
   deleteSelectedEndpoints() {
   deleteSelectedEndpoints() {
@@ -193,18 +193,17 @@ class EndpointsPage extends React.Component<{ history: any }, State> {
     }
     }
   }
   }
 
 
-  pollData(showLoading?: boolean = false) {
+  async pollData(showLoading?: boolean = false) {
     if (this.state.modalIsOpen || this.stopPolling) {
     if (this.state.modalIsOpen || this.stopPolling) {
       return
       return
     }
     }
 
 
-    Promise.all([
+    await Promise.all([
       endpointStore.getEndpoints({ showLoading, skipLog: true }),
       endpointStore.getEndpoints({ showLoading, skipLog: true }),
       migrationStore.getMigrations({ skipLog: true }),
       migrationStore.getMigrations({ skipLog: true }),
       replicaStore.getReplicas({ skipLog: true }),
       replicaStore.getReplicas({ skipLog: true }),
-    ]).then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    ])
+    this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   itemFilterFunction(item: any, filterItem?: ?string, filterText?: string) {
   itemFilterFunction(item: any, filterItem?: ?string, filterText?: string) {

+ 33 - 33
src/components/pages/MigrationDetailsPage/MigrationDetailsPage.jsx

@@ -85,24 +85,23 @@ class MigrationDetailsPage extends React.Component<Props, State> {
     this.stopPolling = true
     this.stopPolling = true
   }
   }
 
 
-  loadMigrationWithInstances(migrationId: string, cache: boolean) {
-    migrationStore.getMigration(migrationId, { showLoading: true }).then(() => {
-      let details = migrationStore.migrationDetails
-      if (!details) {
-        return
-      }
-
-      networkStore.loadNetworks(details.destination_endpoint_id, details.destination_environment, {
-        quietError: true,
-        useLocalStorage: cache,
-      })
-      instanceStore.loadInstancesDetails(
-        details.origin_endpoint_id,
-        // $FlowIgnore
-        details.instances.map(n => { return { instance_name: n } }),
-        false, cache
-      )
+  async loadMigrationWithInstances(migrationId: string, cache: boolean) {
+    await migrationStore.getMigration(migrationId, { showLoading: true })
+    let details = migrationStore.migrationDetails
+    if (!details) {
+      return
+    }
+
+    networkStore.loadNetworks(details.destination_endpoint_id, details.destination_environment, {
+      quietError: true,
+      useLocalStorage: cache,
     })
     })
+    instanceStore.loadInstancesDetails(
+      details.origin_endpoint_id,
+      // $FlowIgnore
+      details.instances.map(n => { return { instance_name: n } }),
+      false, cache
+    )
   }
   }
 
 
   handleUserItemClick(item: { value: string }) {
   handleUserItemClick(item: { value: string }) {
@@ -151,39 +150,40 @@ class MigrationDetailsPage extends React.Component<Props, State> {
     this.setState({ showCancelConfirmation: false })
     this.setState({ showCancelConfirmation: false })
   }
   }
 
 
-  handleCancelConfirmation() {
+  async handleCancelConfirmation() {
     this.setState({ showCancelConfirmation: false })
     this.setState({ showCancelConfirmation: false })
     if (!migrationStore.migrationDetails) {
     if (!migrationStore.migrationDetails) {
       return
       return
     }
     }
-    migrationStore.cancel(migrationStore.migrationDetails.id).then(() => {
-      if (migrationStore.canceling === false) {
-        notificationStore.alert('Canceled', 'success')
-      } else {
-        notificationStore.alert('The migration couldn\'t be canceled', 'error')
-      }
-    })
+    await migrationStore.cancel(migrationStore.migrationDetails.id)
+    if (migrationStore.canceling === false) {
+      notificationStore.alert('Canceled', 'success')
+    } else {
+      notificationStore.alert('The migration couldn\'t be canceled', 'error')
+    }
   }
   }
 
 
-  recreateFromReplica(options: Field[]) {
+  async recreateFromReplica(options: Field[]) {
     let replicaId = migrationStore.migrationDetails && migrationStore.migrationDetails.replica_id
     let replicaId = migrationStore.migrationDetails && migrationStore.migrationDetails.replica_id
     if (!replicaId) {
     if (!replicaId) {
       return
       return
     }
     }
 
 
-    migrationStore.migrateReplica(replicaId, options).then(migration => {
-      this.props.history.push(`/migration/tasks/${migration.id}`)
-    })
+    this.migrate(replicaId, options)
     this.handleCloseFromReplicaModal()
     this.handleCloseFromReplicaModal()
   }
   }
 
 
-  pollData() {
+  async migrate(replicaId: string, options: Field[]) {
+    let migration = await migrationStore.migrateReplica(replicaId, options)
+    this.props.history.push(`/migration/tasks/${migration.id}`)
+  }
+
+  async pollData() {
     if (this.state.showEditModal || this.stopPolling) {
     if (this.state.showEditModal || this.stopPolling) {
       return
       return
     }
     }
-    migrationStore.getMigration(this.props.match.params.id, { showLoading: false, skipLog: true }).then(() => {
-      setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    await migrationStore.getMigration(this.props.match.params.id, { showLoading: false, skipLog: true })
+    setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   getStatus() {
   getStatus() {

+ 3 - 7
src/components/pages/MigrationsPage/MigrationsPage.jsx

@@ -167,17 +167,13 @@ class MigrationsPage extends React.Component<{ history: any }, State> {
     return true
     return true
   }
   }
 
 
-  pollData() {
+  async pollData() {
     if (this.state.modalIsOpen || this.stopPolling) {
     if (this.state.modalIsOpen || this.stopPolling) {
       return
       return
     }
     }
 
 
-    Promise.all([
-      migrationStore.getMigrations({ skipLog: true }),
-      endpointStore.getEndpoints({ skipLog: true }),
-    ]).then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    await Promise.all([migrationStore.getMigrations({ skipLog: true }), endpointStore.getEndpoints({ skipLog: true })])
+    this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   render() {
   render() {

+ 40 - 48
src/components/pages/ProjectDetailsPage/ProjectDetailsPage.jsx

@@ -76,25 +76,21 @@ class ProjectDetailsPage extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
-  handleEnableUser(user: User) {
+  async handleEnableUser(user: User) {
     let enabled = !user.enabled
     let enabled = !user.enabled
     // $FlowIgnore
     // $FlowIgnore
-    userStore.update(user.id, { enabled }).then(() => {
-      projectStore.getUsers(this.props.match.params.id)
-    })
+    await userStore.update(user.id, { enabled })
+    projectStore.getUsers(this.props.match.params.id)
   }
   }
 
 
-  handleUserRoleChange(user: User, roleId: string, toggled: boolean) {
+  async handleUserRoleChange(user: User, roleId: string, toggled: boolean) {
     let projectId = this.props.match.params.id
     let projectId = this.props.match.params.id
-    let operation: Promise<void>
     if (toggled) {
     if (toggled) {
-      operation = projectStore.assignUserRole(projectId, user.id, roleId)
+      await projectStore.assignUserRole(projectId, user.id, roleId)
     } else {
     } else {
-      operation = projectStore.removeUserRole(projectId, user.id, roleId)
+      await projectStore.removeUserRole(projectId, user.id, roleId)
     }
     }
-    operation.then(() => {
-      projectStore.getRoleAssignments()
-    })
+    projectStore.getRoleAssignments()
   }
   }
 
 
   handleRemoveUser(user: User) {
   handleRemoveUser(user: User) {
@@ -113,48 +109,45 @@ class ProjectDetailsPage extends React.Component<Props, State> {
     this.setState({ showProjectModal: false })
     this.setState({ showProjectModal: false })
   }
   }
 
 
-  handleProjectUpdateClick(project: Project) {
-    projectStore.update(this.props.match.params.id, project).then(() => {
-      this.setState({ showProjectModal: false })
-    })
+  async handleProjectUpdateClick(project: Project) {
+    await projectStore.update(this.props.match.params.id, project)
+    this.setState({ showProjectModal: false })
   }
   }
 
 
-  handleDeleteConfirmation() {
+  async handleDeleteConfirmation() {
     this.setState({ showDeleteProjectAlert: false })
     this.setState({ showDeleteProjectAlert: false })
 
 
-    projectStore.delete(this.props.match.params.id).then(() => {
-      if (
-        userStore.loggedUser &&
-        this.props.match.params.id === userStore.loggedUser.project.id &&
-        projectStore.projects.length > 0
-      ) {
-        userStore.switchProject(projectStore.projects[0].id).then(() => {
-          projectStore.getProjects()
-          this.props.history.push('/projects')
-        })
-      } else {
-        this.props.history.push('/projects')
-      }
-    })
+    await projectStore.delete(this.props.match.params.id)
+    if (
+      userStore.loggedUser &&
+      this.props.match.params.id === userStore.loggedUser.project.id &&
+      projectStore.projects.length > 0
+    ) {
+      await userStore.switchProject(projectStore.projects[0].id)
+      projectStore.getProjects()
+      this.props.history.push('/projects')
+    } else {
+      this.props.history.push('/projects')
+    }
   }
   }
 
 
-  handleAddMemberClick() {
-    userStore.getAllUsers().then(() => {
-      this.setState({ showAddMemberModal: true })
-    })
+  async handleAddMemberClick() {
+    await userStore.getAllUsers()
+    this.setState({ showAddMemberModal: true })
   }
   }
 
 
-  handleAddMember(user: User, isNew: boolean, roles: Role[]) {
-    const assign = (userId: string) => {
-      Promise.all(roles.map(r => {
-        return userStore.assignUserToProjectWithRole(userId, this.props.match.params.id, r.id)
-      })).catch(e => {
-        notificationStore.alert('Error while assigning role to user', 'error')
-        console.error(e)
-      }).then(() => {
+  async handleAddMember(user: User, isNew: boolean, roles: Role[]) {
+    const assign = async (userId: string) => {
+      try {
+        await Promise.all(roles.map(async r => {
+          await userStore.assignUserToProjectWithRole(userId, this.props.match.params.id, r.id)
+        }))
         this.loadData()
         this.loadData()
         this.setState({ addingMember: false, showAddMemberModal: false })
         this.setState({ addingMember: false, showAddMemberModal: false })
-      })
+      } catch (err) {
+        notificationStore.alert('Error while assigning role to user', 'error')
+        console.error(err)
+      }
     }
     }
 
 
     this.setState({ addingMember: true })
     this.setState({ addingMember: true })
@@ -164,11 +157,10 @@ class ProjectDetailsPage extends React.Component<Props, State> {
       return
       return
     }
     }
 
 
-    userStore.add(user).then((addedUser: ?User) => {
-      if (addedUser) {
-        assign(addedUser.id)
-      }
-    })
+    let addedUser: ?User = await userStore.add(user)
+    if (addedUser) {
+      assign(addedUser.id)
+    }
   }
   }
 
 
   handleDeleteProjectClick() {
   handleDeleteProjectClick() {

+ 7 - 9
src/components/pages/ProjectsPage/ProjectsPage.jsx

@@ -80,23 +80,21 @@ class ProjectsPage extends React.Component<{ history: any }, State> {
     projectStore.getRoleAssignments()
     projectStore.getRoleAssignments()
   }
   }
 
 
-  handleSwitchProjectClick(projectId: string) {
-    userStore.switchProject(projectId).then(() => {
-      projectStore.getProjects()
-    })
+  async handleSwitchProjectClick(projectId: string) {
+    await userStore.switchProject(projectId)
+    projectStore.getProjects()
   }
   }
 
 
-  pollData(showLoading?: boolean) {
+  async pollData(showLoading?: boolean) {
     if (this.state.modalIsOpen || this.stopPolling) {
     if (this.state.modalIsOpen || this.stopPolling) {
       return
       return
     }
     }
 
 
-    Promise.all([
+    await Promise.all([
       projectStore.getProjects({ showLoading, skipLog: true }),
       projectStore.getProjects({ showLoading, skipLog: true }),
       projectStore.getRoleAssignments({ skipLog: true }),
       projectStore.getRoleAssignments({ skipLog: true }),
-    ]).then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    ])
+    this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   itemFilterFunction(item: Project, filterItem?: ?string, filterText?: string): boolean {
   itemFilterFunction(item: Project, filterItem?: ?string, filterText?: string): boolean {

+ 49 - 50
src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.jsx

@@ -105,46 +105,43 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
     this.stopPolling = true
     this.stopPolling = true
   }
   }
 
 
-  loadIsEditable(replicaDetails: MainItem) {
+  async loadIsEditable(replicaDetails: MainItem) {
     let targetEndpointId = replicaDetails.destination_endpoint_id
     let targetEndpointId = replicaDetails.destination_endpoint_id
     let sourceEndpointId = replicaDetails.origin_endpoint_id
     let sourceEndpointId = replicaDetails.origin_endpoint_id
-    providerStore.loadProviders()
-      .then(() => utils.waitFor(() => endpointStore.endpoints.length > 0))
-      .then(() => {
-        let sourceEndpoint = endpointStore.endpoints.find(e => e.id === sourceEndpointId)
-        let targetEndpoint = endpointStore.endpoints.find(e => e.id === targetEndpointId)
-        if (!sourceEndpoint || !targetEndpoint || !providerStore.providers) {
-          return
-        }
-        let sourceProviderTypes = providerStore.providers[sourceEndpoint.type]
-        let targetProviderTypes = providerStore.providers[targetEndpoint.type]
-        let isEditable = sourceProviderTypes && targetProviderTypes ?
-          !!sourceProviderTypes.types.find(t => t === providerTypes.SOURCE_UPDATE)
-          && !!targetProviderTypes.types.find(t => t === providerTypes.TARGET_UPDATE)
-          : false
-
-        this.setState({ isEditable })
-      })
-  }
-
-  loadReplicaWithInstances(replicaId: string, cache: boolean) {
-    replicaStore.getReplica(replicaId, { showLoading: true }).then(() => {
-      let details = replicaStore.replicaDetails
-      if (!details) {
-        return
-      }
-      this.loadIsEditable(details)
-      networkStore.loadNetworks(details.destination_endpoint_id, details.destination_environment, {
-        quietError: true,
-        useLocalStorage: cache,
-      })
-      instanceStore.loadInstancesDetails(
-        details.origin_endpoint_id,
-        // $FlowIgnore
-        details.instances.map(n => { return { instance_name: n } }),
-        false, cache
-      )
+    await providerStore.loadProviders()
+    await utils.waitFor(() => endpointStore.endpoints.length > 0)
+    let sourceEndpoint = endpointStore.endpoints.find(e => e.id === sourceEndpointId)
+    let targetEndpoint = endpointStore.endpoints.find(e => e.id === targetEndpointId)
+    if (!sourceEndpoint || !targetEndpoint || !providerStore.providers) {
+      return
+    }
+    let sourceProviderTypes = providerStore.providers[sourceEndpoint.type]
+    let targetProviderTypes = providerStore.providers[targetEndpoint.type]
+    let isEditable = sourceProviderTypes && targetProviderTypes ?
+      !!sourceProviderTypes.types.find(t => t === providerTypes.SOURCE_UPDATE)
+      && !!targetProviderTypes.types.find(t => t === providerTypes.TARGET_UPDATE)
+      : false
+
+    this.setState({ isEditable })
+  }
+
+  async loadReplicaWithInstances(replicaId: string, cache: boolean) {
+    await replicaStore.getReplica(replicaId, { showLoading: true })
+    let details = replicaStore.replicaDetails
+    if (!details) {
+      return
+    }
+    this.loadIsEditable(details)
+    networkStore.loadNetworks(details.destination_endpoint_id, details.destination_environment, {
+      quietError: true,
+      useLocalStorage: cache,
     })
     })
+    instanceStore.loadInstancesDetails(
+      details.origin_endpoint_id,
+      // $FlowIgnore
+      details.instances.map(n => { return { instance_name: n } }),
+      false, cache
+    )
   }
   }
 
 
   getLastExecution() {
   getLastExecution() {
@@ -292,17 +289,20 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
   }
   }
 
 
   migrateReplica(options: Field[]) {
   migrateReplica(options: Field[]) {
-    migrationStore.migrateReplica(replicaStore.replicaDetails ? replicaStore.replicaDetails.id : '', options).then(migration => {
-      notificationStore.alert('Migration successfully created from replica.', 'success', {
-        action: {
-          label: 'View Migration Status',
-          callback: () => {
-            this.props.history.push(`/migration/tasks/${migration.id}`)
-          },
+    this.migrate(options)
+    this.handleCloseMigrationModal()
+  }
+
+  async migrate(options: Field[]) {
+    let migration = await migrationStore.migrateReplica(replicaStore.replicaDetails ? replicaStore.replicaDetails.id : '', options)
+    notificationStore.alert('Migration successfully created from replica.', 'success', {
+      action: {
+        label: 'View Migration Status',
+        callback: () => {
+          this.props.history.push(`/migration/tasks/${migration.id}`)
         },
         },
-      })
+      },
     })
     })
-    this.handleCloseMigrationModal()
   }
   }
 
 
   executeReplica(fields: Field[]) {
   executeReplica(fields: Field[]) {
@@ -311,7 +311,7 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
     this.props.history.push(`/replica/executions/${replicaStore.replicaDetails ? replicaStore.replicaDetails.id : ''}`)
     this.props.history.push(`/replica/executions/${replicaStore.replicaDetails ? replicaStore.replicaDetails.id : ''}`)
   }
   }
 
 
-  pollData(showLoading: boolean) {
+  async pollData(showLoading: boolean) {
     if (this.state.showEditModal || this.stopPolling) {
     if (this.state.showEditModal || this.stopPolling) {
       return
       return
     }
     }
@@ -320,9 +320,8 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
       replicaStore.getReplica(this.props.match.params.id, { showLoading, skipLog: true })
       replicaStore.getReplica(this.props.match.params.id, { showLoading, skipLog: true })
     }
     }
 
 
-    replicaStore.getReplicaExecutions(this.props.match.params.id, { showLoading, skipLog: true }).then(() => {
-      setTimeout(() => { this.pollData(false) }, configLoader.config.requestPollTimeout)
-    })
+    await replicaStore.getReplicaExecutions(this.props.match.params.id, { showLoading, skipLog: true })
+    setTimeout(() => { this.pollData(false) }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   closeEditModal() {
   closeEditModal() {

+ 18 - 20
src/components/pages/ReplicasPage/ReplicasPage.jsx

@@ -144,13 +144,16 @@ class ReplicasPage extends React.Component<{ history: any }, State> {
 
 
   migrateSelectedReplicas(fields: Field[]) {
   migrateSelectedReplicas(fields: Field[]) {
     notificationStore.alert('Creating migrations from selected replicas')
     notificationStore.alert('Creating migrations from selected replicas')
-    Promise.all(this.state.selectedReplicas.map(replica => migrationStore.migrateReplica(replica.id, fields))).then(() => {
-      notificationStore.alert('Migrations successfully created from replicas.', 'success')
-      this.props.history.push('/migrations')
-    })
+    this.migrate(fields)
     this.setState({ showCreateMigrationsModal: false })
     this.setState({ showCreateMigrationsModal: false })
   }
   }
 
 
+  async migrate(fields: Field[]) {
+    await Promise.all(this.state.selectedReplicas.map(replica => migrationStore.migrateReplica(replica.id, fields)))
+    notificationStore.alert('Migrations successfully created from replicas.', 'success')
+    this.props.history.push('/migrations')
+  }
+
   deleteSelectedReplicasDisks() {
   deleteSelectedReplicasDisks() {
     this.state.selectedReplicas.forEach(replica => {
     this.state.selectedReplicas.forEach(replica => {
       replicaStore.deleteDisks(replica.id)
       replicaStore.deleteDisks(replica.id)
@@ -212,32 +215,27 @@ class ReplicasPage extends React.Component<{ history: any }, State> {
     })
     })
   }
   }
 
 
-  pollData() {
+  async pollData() {
     if (this.state.modalIsOpen || this.stopPolling) {
     if (this.state.modalIsOpen || this.stopPolling) {
       return
       return
     }
     }
 
 
-    Promise.all([
-      replicaStore.getReplicas({ skipLog: true }),
-      endpointStore.getEndpoints({ skipLog: true }),
-    ]).then(() => {
-      if (!this.schedulePolling) {
-        this.pollSchedule()
-      }
-      this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    await Promise.all([replicaStore.getReplicas({ skipLog: true }), endpointStore.getEndpoints({ skipLog: true })])
+    if (!this.schedulePolling) {
+      this.pollSchedule()
+    }
+    this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
-  pollSchedule() {
+  async pollSchedule() {
     if (this.state.modalIsOpen || this.stopPolling || replicaStore.replicas.length === 0) {
     if (this.state.modalIsOpen || this.stopPolling || replicaStore.replicas.length === 0) {
       return
       return
     }
     }
     this.schedulePolling = true
     this.schedulePolling = true
-    scheduleStore.getSchedulesBulk(replicaStore.replicas.map(r => r.id)).then(() => {
-      this.schedulePollTimeout = setTimeout(() => {
-        this.pollSchedule()
-      }, SCHEDULE_POLL_TIMEOUT)
-    })
+    await scheduleStore.getSchedulesBulk(replicaStore.replicas.map(r => r.id))
+    this.schedulePollTimeout = setTimeout(() => {
+      this.pollSchedule()
+    }, SCHEDULE_POLL_TIMEOUT)
   }
   }
 
 
   searchText(item: MainItem, text: ?string) {
   searchText(item: MainItem, text: ?string) {

+ 7 - 9
src/components/pages/UserDetailsPage/UserDetailsPage.jsx

@@ -82,21 +82,19 @@ class UserDetailsPage extends React.Component<Props, State> {
     this.setState({ showUserModal: true })
     this.setState({ showUserModal: true })
   }
   }
 
 
-  handleDeleteConfirmation() {
-    userStore.delete(this.props.match.params.id).then(() => {
-      this.props.history.push('/users')
-    })
+  async handleDeleteConfirmation() {
+    await userStore.delete(this.props.match.params.id)
+    this.props.history.push('/users')
   }
   }
 
 
   handleUserEditModalClose() {
   handleUserEditModalClose() {
     this.setState({ showUserModal: false, editPassword: false })
     this.setState({ showUserModal: false, editPassword: false })
   }
   }
 
 
-  handleUserUpdateClick(user: User) {
-    userStore.update(this.props.match.params.id, user).then(() => {
-      userStore.getProjects(this.props.match.params.id)
-      this.setState({ showUserModal: false, editPassword: false })
-    })
+  async handleUserUpdateClick(user: User) {
+    await userStore.update(this.props.match.params.id, user)
+    userStore.getProjects(this.props.match.params.id)
+    this.setState({ showUserModal: false, editPassword: false })
   }
   }
 
 
   handleUpdatePasswordClick() {
   handleUpdatePasswordClick() {

+ 3 - 4
src/components/pages/UsersPage/UsersPage.jsx

@@ -82,14 +82,13 @@ class UsersPage extends React.Component<{ history: any }, State> {
     userStore.getAllUsers({ showLoading: true })
     userStore.getAllUsers({ showLoading: true })
   }
   }
 
 
-  pollData(showLoading?: boolean) {
+  async pollData(showLoading?: boolean) {
     if (this.state.modalIsOpen || this.stopPolling) {
     if (this.state.modalIsOpen || this.stopPolling) {
       return
       return
     }
     }
 
 
-    userStore.getAllUsers({ showLoading, skipLog: true }).then(() => {
-      this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
-    })
+    await userStore.getAllUsers({ showLoading, skipLog: true })
+    this.pollTimeout = setTimeout(() => { this.pollData() }, configLoader.config.requestPollTimeout)
   }
   }
 
 
   itemFilterFunction(item: User, filterItem?: ?string, filterText?: string): boolean {
   itemFilterFunction(item: User, filterItem?: ?string, filterText?: string): boolean {

+ 88 - 68
src/components/pages/WizardPage/WizardPage.jsx

@@ -137,7 +137,7 @@ class WizardPage extends React.Component<Props, State> {
     this.handleBackClick()
     this.handleBackClick()
   }
   }
 
 
-  handleCreationSuccess(items: MainItem[]) {
+  async handleCreationSuccess(items: MainItem[]) {
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     notificationStore.alert(`${typeLabel} was succesfully created`, 'success')
     notificationStore.alert(`${typeLabel} was succesfully created`, 'success')
     let schedulePromise = Promise.resolve()
     let schedulePromise = Promise.resolve()
@@ -156,9 +156,8 @@ class WizardPage extends React.Component<Props, State> {
       } else {
       } else {
         location += 'tasks/'
         location += 'tasks/'
       }
       }
-      schedulePromise.then(() => {
-        this.props.history.push(location + items[0].id)
-      })
+      await schedulePromise
+      this.props.history.push(location + items[0].id)
     } else {
     } else {
       this.props.history.push(`/${this.state.type}s`)
       this.props.history.push(`/${this.state.type}s`)
     }
     }
@@ -213,50 +212,62 @@ class WizardPage extends React.Component<Props, State> {
     wizardStore.setCurrentPage(page)
     wizardStore.setCurrentPage(page)
   }
   }
 
 
-  handleSourceEndpointChange(source: ?EndpointType) {
+  async handleSourceEndpointChange(source: ?EndpointType) {
     wizardStore.updateData({ source, selectedInstances: null, networks: null, sourceOptions: null })
     wizardStore.updateData({ source, selectedInstances: null, networks: null, sourceOptions: null })
     wizardStore.clearStorageMap()
     wizardStore.clearStorageMap()
     wizardStore.setPermalink(wizardStore.data)
     wizardStore.setPermalink(wizardStore.data)
 
 
+    let getConnectionInfo = async () => {
+      if (!source) {
+        return
+      }
+      // Check if user has permission for this endpoint
+      try {
+        await endpointStore.getConnectionInfo(source)
+        if (source) {
+          // Preload instances for 'vms' page
+          instanceStore.loadInstancesInChunks(source, this.instancesPerPage)
+        }
+      } catch (err) {
+        this.handleSourceEndpointChange(null)
+      }
+    }
+    getConnectionInfo()
+
     if (!source) {
     if (!source) {
       return
       return
     }
     }
-
-    // Check if user has permission for this endpoint
-    endpointStore.getConnectionInfo(source).then(() => {
-      if (source) {
-        // Preload instances for 'vms' page
-        instanceStore.loadInstancesInChunks(source, this.instancesPerPage)
-      }
-    }).catch(() => {
-      this.handleSourceEndpointChange(null)
+    await providerStore.loadOptionsSchema({
+      providerName: source.type,
+      schemaType: this.state.type,
+      optionsType: 'source',
     })
     })
-
-    providerStore.loadSourceSchema(source.type, this.state.type).then(() => {
-      source && providerStore.getOptionsValues({
-        optionsType: 'source',
-        endpointId: source.id,
-        provider: source.type,
-      })
+    source && providerStore.getOptionsValues({
+      optionsType: 'source',
+      endpointId: source.id,
+      providerName: source.type,
     })
     })
   }
   }
 
 
-  handleTargetEndpointChange(target: EndpointType) {
+  async handleTargetEndpointChange(target: EndpointType) {
     wizardStore.updateData({ target, networks: null, destOptions: null })
     wizardStore.updateData({ target, networks: null, destOptions: null })
     wizardStore.clearStorageMap()
     wizardStore.clearStorageMap()
     wizardStore.setPermalink(wizardStore.data)
     wizardStore.setPermalink(wizardStore.data)
-    // Preload destination options schema
-    providerStore.loadDestinationSchema(target.type, this.state.type).then(() => {
-      // Preload destination options values
-      providerStore.getOptionsValues({
-        optionsType: 'destination',
-        endpointId: target.id,
-        provider: target.type,
-      })
-    })
     if (this.pages.find(p => p.id === 'storage')) {
     if (this.pages.find(p => p.id === 'storage')) {
       endpointStore.loadStorage(target.id, {})
       endpointStore.loadStorage(target.id, {})
     }
     }
+    // Preload destination options schema
+    await providerStore.loadOptionsSchema({
+      providerName: target.type,
+      schemaType: this.state.type,
+      optionsType: 'destination',
+    })
+    // Preload destination options values
+    providerStore.getOptionsValues({
+      optionsType: 'destination',
+      endpointId: target.id,
+      providerName: target.type,
+    })
   }
   }
 
 
   handleAddEndpoint(newEndpointType: string, newEndpointFromSource: boolean) {
   handleAddEndpoint(newEndpointType: string, newEndpointFromSource: boolean) {
@@ -352,26 +363,26 @@ class WizardPage extends React.Component<Props, State> {
   }
   }
 
 
   loadEnvDestinationOptions(field?: Field) {
   loadEnvDestinationOptions(field?: Field) {
-    let provider = wizardStore.data.target && wizardStore.data.target.type
+    let providerName = wizardStore.data.target && wizardStore.data.target.type
     let envData = getFieldChangeOptions({
     let envData = getFieldChangeOptions({
-      provider: wizardStore.data.target && wizardStore.data.target.type,
+      providerName: wizardStore.data.target && wizardStore.data.target.type,
       schema: providerStore.destinationSchema,
       schema: providerStore.destinationSchema,
       data: wizardStore.data.destOptions,
       data: wizardStore.data.destOptions,
       field,
       field,
       type: 'destination',
       type: 'destination',
     })
     })
 
 
-    if (provider && envData && wizardStore.data.target) {
+    if (providerName && envData && wizardStore.data.target) {
       providerStore.getOptionsValues({
       providerStore.getOptionsValues({
         optionsType: 'destination',
         optionsType: 'destination',
         endpointId: wizardStore.data.target.id,
         endpointId: wizardStore.data.target.id,
-        provider,
+        providerName,
         envData,
         envData,
       })
       })
     }
     }
   }
   }
 
 
-  loadDataForPage(page: WizardPageType) {
+  async loadDataForPage(page: WizardPageType) {
     switch (page.id) {
     switch (page.id) {
       case 'source': {
       case 'source': {
         providerStore.loadProviders()
         providerStore.loadProviders()
@@ -383,26 +394,33 @@ class WizardPage extends React.Component<Props, State> {
         }
         }
 
 
         if (providerStore.sourceSchema.length === 0 && source) {
         if (providerStore.sourceSchema.length === 0 && source) {
-          providerStore.loadSourceSchema(source.type, this.state.type).then(() => {
+          let loadOptionsSchema = async () => {
+            await providerStore.loadOptionsSchema({
+              providerName: source.type,
+              schemaType: this.state.type,
+              optionsType: 'source',
+            })
             // Preload source options if data is set from 'Permalink'
             // Preload source options if data is set from 'Permalink'
             if (providerStore.sourceOptions.length === 0 && source) {
             if (providerStore.sourceOptions.length === 0 && source) {
               providerStore.getOptionsValues({
               providerStore.getOptionsValues({
                 optionsType: 'source',
                 optionsType: 'source',
                 endpointId: source.id,
                 endpointId: source.id,
-                provider: source.type,
+                providerName: source.type,
               })
               })
             }
             }
-          })
+          }
+          loadOptionsSchema()
         }
         }
 
 
         if (instanceStore.instances.length === 0) {
         if (instanceStore.instances.length === 0) {
-          // Check if user has permission for this endpoint
-          endpointStore.getConnectionInfo(source).then(() => {
+          try {
+            // Check if user has permission for this endpoint
+            await endpointStore.getConnectionInfo(source)
             // Preload instances for 'vms' page
             // Preload instances for 'vms' page
             instanceStore.loadInstancesInChunks(source, this.instancesPerPage)
             instanceStore.loadInstancesInChunks(source, this.instancesPerPage)
-          }).catch(() => {
+          } catch (err) {
             this.handleSourceEndpointChange(null)
             this.handleSourceEndpointChange(null)
-          })
+          }
         }
         }
         break
         break
       }
       }
@@ -414,18 +432,20 @@ class WizardPage extends React.Component<Props, State> {
         }
         }
         // Preload destination options schema
         // Preload destination options schema
         if (providerStore.destinationSchema.length === 0 && target) {
         if (providerStore.destinationSchema.length === 0 && target) {
-          providerStore.loadDestinationSchema(target.type, this.state.type).then(() => {
-            // Preload destination options if data is set from 'Permalink'
-            if (providerStore.destinationOptions.length === 0 && target) {
-              providerStore.getOptionsValues({
-                optionsType: 'destination',
-                endpointId: target.id,
-                provider: target.type,
-              }).then(() => {
-                this.loadEnvDestinationOptions()
-              })
-            }
+          await providerStore.loadOptionsSchema({
+            providerName: target.type,
+            schemaType: this.state.type,
+            optionsType: 'destination',
           })
           })
+          // Preload destination options if data is set from 'Permalink'
+          if (providerStore.destinationOptions.length === 0 && target) {
+            await providerStore.getOptionsValues({
+              optionsType: 'destination',
+              endpointId: target.id,
+              providerName: target.type,
+            })
+            this.loadEnvDestinationOptions()
+          }
         }
         }
         break
         break
       }
       }
@@ -442,24 +462,24 @@ class WizardPage extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
-  createMultiple() {
+  async createMultiple() {
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     notificationStore.alert(`Creating ${typeLabel}s ...`)
     notificationStore.alert(`Creating ${typeLabel}s ...`)
-    wizardStore.createMultiple(this.state.type, wizardStore.data, wizardStore.storageMap).then(() => {
-      let items = wizardStore.createdItems
-      if (!items) {
-        notificationStore.alert(`${typeLabel}s couldn't be created`, 'error')
-        this.setState({ nextButtonDisabled: false })
-        return
-      }
-      this.handleCreationSuccess(items)
-    })
+    await wizardStore.createMultiple(this.state.type, wizardStore.data, wizardStore.storageMap)
+    let items = wizardStore.createdItems
+    if (!items) {
+      notificationStore.alert(`${typeLabel}s couldn't be created`, 'error')
+      this.setState({ nextButtonDisabled: false })
+      return
+    }
+    this.handleCreationSuccess(items)
   }
   }
 
 
-  createSingle() {
+  async createSingle() {
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     let typeLabel = this.state.type.charAt(0).toUpperCase() + this.state.type.substr(1)
     notificationStore.alert(`Creating ${typeLabel} ...`)
     notificationStore.alert(`Creating ${typeLabel} ...`)
-    wizardStore.create(this.state.type, wizardStore.data, wizardStore.storageMap).then(() => {
+    try {
+      await wizardStore.create(this.state.type, wizardStore.data, wizardStore.storageMap)
       let item = wizardStore.createdItem
       let item = wizardStore.createdItem
       if (!item) {
       if (!item) {
         notificationStore.alert(`${typeLabel} couldn't be created`, 'error')
         notificationStore.alert(`${typeLabel} couldn't be created`, 'error')
@@ -467,9 +487,9 @@ class WizardPage extends React.Component<Props, State> {
         return
         return
       }
       }
       this.handleCreationSuccess([item])
       this.handleCreationSuccess([item])
-    }).catch(() => {
+    } catch (err) {
       this.setState({ nextButtonDisabled: false })
       this.setState({ nextButtonDisabled: false })
-    })
+    }
   }
   }
 
 
   separateVms() {
   separateVms() {

+ 119 - 118
src/sources/EndpointSource.js

@@ -39,107 +39,108 @@ let getBarbicanPayload = data => {
   }
   }
 }
 }
 
 
-class EdnpointSource {
-  static getEndpoints(skipLog?: boolean): Promise<Endpoint[]> {
-    return Api.send({
+class EndpointSource {
+  async getEndpoints(skipLog?: boolean): Promise<Endpoint[]> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let connections = []
-      if (response.data.endpoints.length) {
-        response.data.endpoints.forEach(endpoint => {
-          connections.push(SchemaParser.parseConnectionResponse(endpoint))
-        })
-      }
-
-      connections.sort((c1, c2) => moment(c2.created_at).diff(moment(c1.created_at)))
-      return connections
     })
     })
+    let connections = []
+    if (response.data.endpoints.length) {
+      response.data.endpoints.forEach(endpoint => {
+        connections.push(SchemaParser.parseConnectionResponse(endpoint))
+      })
+    }
+
+    connections.sort((c1, c2) => moment(c2.created_at).diff(moment(c1.created_at)))
+    return connections
   }
   }
-  static delete(endpoint: Endpoint): Promise<string> {
-    return Api.send({
+
+  async delete(endpoint: Endpoint): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => {
-      if (endpoint.connection_info && endpoint.connection_info.secret_ref) {
-        let uuidIndex = endpoint.connection_info.secret_ref.lastIndexOf('/')
-        // $FlowIssue
-        let uuid = endpoint.connection_info.secret_ref.substr(uuidIndex + 1)
-        return Api.send({
-          url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
-          method: 'DELETE',
-        }).then(() => { return endpoint.id })
-      }
-      return endpoint.id
     })
     })
+    if (endpoint.connection_info && endpoint.connection_info.secret_ref) {
+      let uuidIndex = endpoint.connection_info.secret_ref.lastIndexOf('/')
+      // $FlowIssue
+      let uuid = endpoint.connection_info.secret_ref.substr(uuidIndex + 1)
+      await Api.send({
+        url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
+        method: 'DELETE',
+      })
+      return endpoint.id
+    }
+    return endpoint.id
   }
   }
 
 
-  static getConnectionInfo(endpoint: Endpoint): Promise<$PropertyType<Endpoint, 'connection_info'>> {
+  async getConnectionInfo(endpoint: Endpoint): Promise<$PropertyType<Endpoint, 'connection_info'>> {
     let index = endpoint.connection_info.secret_ref && endpoint.connection_info.secret_ref.lastIndexOf('/')
     let index = endpoint.connection_info.secret_ref && endpoint.connection_info.secret_ref.lastIndexOf('/')
     let uuid = index && endpoint.connection_info.secret_ref && endpoint.connection_info.secret_ref.substr(index + 1)
     let uuid = index && endpoint.connection_info.secret_ref && endpoint.connection_info.secret_ref.substr(index + 1)
 
 
     if (!uuid) {
     if (!uuid) {
-      return Promise.resolve(endpoint.connection_info)
+      return endpoint.connection_info
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.barbican}/v1/secrets/${uuid || 'undefined'}/payload`,
       url: `${servicesUrl.barbican}/v1/secrets/${uuid || 'undefined'}/payload`,
       responseType: 'text',
       responseType: 'text',
       headers: { Accept: 'text/plain' },
       headers: { Accept: 'text/plain' },
-    }).then((response) => {
-      return response.data
     })
     })
+    return response.data
   }
   }
 
 
-  static getSecretPayload(uuid: string, count: number = 0) {
+  async getSecretPayload(uuid: string, count: number = 0) {
     let delay = () => new Promise(r => { setTimeout(() => { r() }, 2000) })
     let delay = () => new Promise(r => { setTimeout(() => { r() }, 2000) })
 
 
     if (count >= 10) {
     if (count >= 10) {
       return Promise.reject({ secretCustomError: `The secret '${uuid}' is not active after ${count} retries.` })
       return Promise.reject({ secretCustomError: `The secret '${uuid}' is not active after ${count} retries.` })
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
       url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
       headers: { Accept: 'application/json' },
       headers: { Accept: 'application/json' },
-    }).then(response => {
-      if (response.data.status === 'ACTIVE') {
-        return Api.send({
-          url: `${servicesUrl.barbican}/v1/secrets/${uuid}/payload`,
-          headers: { Accept: 'text/plain' },
-        })
-      }
-      return delay().then(() => this.getSecretPayload(uuid, count + 1))
     })
     })
+
+    if (response.data.status === 'ACTIVE') {
+      let payload = await Api.send({
+        url: `${servicesUrl.barbican}/v1/secrets/${uuid}/payload`,
+        headers: { Accept: 'text/plain' },
+      })
+      return payload
+    }
+    await delay()
+    let payload = await this.getSecretPayload(uuid, count + 1)
+    return payload
   }
   }
 
 
-  static getConnectionsInfo(endpoints: Endpoint[]): Promise<Endpoint[]> {
-    return Promise.all(endpoints.map(endpoint => {
+  async getConnectionsInfo(endpoints: Endpoint[]): Promise<Endpoint[]> {
+    let result: Endpoint[] = await Promise.all(endpoints.map(async endpoint => {
       let index = endpoint.connection_info.secret_ref ? endpoint.connection_info.secret_ref.lastIndexOf('/') : ''
       let index = endpoint.connection_info.secret_ref ? endpoint.connection_info.secret_ref.lastIndexOf('/') : ''
       let uuid = endpoint.connection_info.secret_ref && index ? endpoint.connection_info.secret_ref.substr(index + 1) : ''
       let uuid = endpoint.connection_info.secret_ref && index ? endpoint.connection_info.secret_ref.substr(index + 1) : ''
       if (!uuid) {
       if (!uuid) {
-        return Promise.resolve({ ...endpoint })
+        return { ...endpoint }
       }
       }
-      return Api.send({
+      let response = await Api.send({
         url: `${servicesUrl.barbican}/v1/secrets/${uuid}/payload`,
         url: `${servicesUrl.barbican}/v1/secrets/${uuid}/payload`,
         responseType: 'text',
         responseType: 'text',
         headers: { Accept: 'text/plain' },
         headers: { Accept: 'text/plain' },
-      }).then(response => {
-        return { ...endpoint, connection_info: response.data }
       })
       })
+      return { ...endpoint, connection_info: response.data }
     }))
     }))
+    return result
   }
   }
 
 
-  static validate(endpoint: Endpoint): Promise<Validation> {
-    return Api.send({
+  async validate(endpoint: Endpoint): Promise<Validation> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}/actions`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}/actions`,
       method: 'POST',
       method: 'POST',
       data: { 'validate-connection': null },
       data: { 'validate-connection': null },
-    }).then(response => {
-      return response.data['validate-connection']
     })
     })
+    return response.data['validate-connection']
   }
   }
 
 
-  static update(endpoint: Endpoint): Promise<Endpoint> {
+  async update(endpoint: Endpoint): Promise<Endpoint> {
     let parsedEndpoint = SchemaParser.fieldsToPayload(endpoint)
     let parsedEndpoint = SchemaParser.fieldsToPayload(endpoint)
 
 
     if (parsedEndpoint.connection_info && Object.keys(parsedEndpoint.connection_info).length > 0 && parsedEndpoint.connection_info.secret_ref) {
     if (parsedEndpoint.connection_info && Object.keys(parsedEndpoint.connection_info).length > 0 && parsedEndpoint.connection_info.secret_ref) {
@@ -149,103 +150,105 @@ class EdnpointSource {
       let uuid = parsedEndpoint.connection_info.secret_ref.substr(uuidIndex + 1)
       let uuid = parsedEndpoint.connection_info.secret_ref.substr(uuidIndex + 1)
       let newEndpoint: any = {}
       let newEndpoint: any = {}
       let connectionInfo = {}
       let connectionInfo = {}
-      return Api.send({
+
+      await Api.send({
         url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
         url: `${servicesUrl.barbican}/v1/secrets/${uuid}`,
         method: 'DELETE',
         method: 'DELETE',
-      }).then(() => {
-        return Api.send({
-          url: `${servicesUrl.barbican}/v1/secrets`,
-          method: 'POST',
-          data: getBarbicanPayload(ObjectUtils.skipField(parsedEndpoint.connection_info, 'secret_ref')),
-        })
-      }).then(response => {
-        connectionInfo = { secret_ref: response.data.secret_ref }
-        let newPayload = {
-          endpoint: {
-            name: parsedEndpoint.name,
-            description: parsedEndpoint.description,
-            connection_info: connectionInfo,
-          },
-        }
-        return Api.send({
-          url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
-          method: 'PUT',
-          data: newPayload,
-        })
-      }).then(putResponse => {
-        uuidIndex = connectionInfo.secret_ref.lastIndexOf('/')
-        uuid = connectionInfo.secret_ref.substr(uuidIndex + 1)
-        newEndpoint = putResponse.data.endpoint
-        return this.getSecretPayload(uuid)
-      }).then(conInfoResponse => {
+      })
+
+      let response = await Api.send({
+        url: `${servicesUrl.barbican}/v1/secrets`,
+        method: 'POST',
+        data: getBarbicanPayload(ObjectUtils.skipField(parsedEndpoint.connection_info, 'secret_ref')),
+      })
+
+      connectionInfo = { secret_ref: response.data.secret_ref }
+      let newPayload = {
+        endpoint: {
+          name: parsedEndpoint.name,
+          description: parsedEndpoint.description,
+          connection_info: connectionInfo,
+        },
+      }
+      let putResponse = await Api.send({
+        url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
+        method: 'PUT',
+        data: newPayload,
+      })
+
+      uuidIndex = connectionInfo.secret_ref.lastIndexOf('/')
+      uuid = connectionInfo.secret_ref.substr(uuidIndex + 1)
+      newEndpoint = putResponse.data.endpoint
+      try {
+        let conInfoResponse = await this.getSecretPayload(uuid)
         newEndpoint.connection_info = {
         newEndpoint.connection_info = {
           ...newEndpoint.connection_info,
           ...newEndpoint.connection_info,
           ...conInfoResponse.data,
           ...conInfoResponse.data,
         }
         }
         return newEndpoint
         return newEndpoint
-      }).catch(e => {
+      } catch (e) {
         if (e.secretCustomError) {
         if (e.secretCustomError) {
           notificationStore.alert(e.secretCustomError, 'error')
           notificationStore.alert(e.secretCustomError, 'error')
         }
         }
         throw e
         throw e
-      })
+      }
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpoint.id}`,
       method: 'PUT',
       method: 'PUT',
       data: { endpoint: parsedEndpoint },
       data: { endpoint: parsedEndpoint },
-    }).then(response => {
-      return SchemaParser.parseConnectionResponse(response.data.endpoint)
     })
     })
+    return SchemaParser.parseConnectionResponse(response.data.endpoint)
   }
   }
 
 
-  static add(endpoint: Endpoint, skipSchemaParser: boolean = false): Promise<Endpoint> {
+  async add(endpoint: Endpoint, skipSchemaParser: boolean = false): Promise<Endpoint> {
     let parsedEndpoint: any = skipSchemaParser ? { ...endpoint } : SchemaParser.fieldsToPayload(endpoint)
     let parsedEndpoint: any = skipSchemaParser ? { ...endpoint } : SchemaParser.fieldsToPayload(endpoint)
     let newEndpoint: any = {}
     let newEndpoint: any = {}
     let connectionInfo = {}
     let connectionInfo = {}
     if (configLoader.config.useBarbicanSecrets
     if (configLoader.config.useBarbicanSecrets
       && parsedEndpoint.connection_info && Object.keys(parsedEndpoint.connection_info).length > 0) {
       && parsedEndpoint.connection_info && Object.keys(parsedEndpoint.connection_info).length > 0) {
-      return Api.send({
+      let response = await Api.send({
         url: `${servicesUrl.barbican}/v1/secrets`,
         url: `${servicesUrl.barbican}/v1/secrets`,
         method: 'POST',
         method: 'POST',
         data: getBarbicanPayload(ObjectUtils.skipField(parsedEndpoint.connection_info, 'secret_ref')),
         data: getBarbicanPayload(ObjectUtils.skipField(parsedEndpoint.connection_info, 'secret_ref')),
-      }).then(response => {
-        connectionInfo = { secret_ref: response.data.secret_ref }
-        let newPayload = {
-          endpoint: {
-            name: parsedEndpoint.name,
-            description: parsedEndpoint.description,
-            type: endpoint.type,
-            connection_info: connectionInfo,
-          },
-        }
-        return Api.send({
-          url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
-          method: 'POST',
-          data: newPayload,
-        })
-      }).then(postResponse => {
-        let uuidIndex = connectionInfo.secret_ref.lastIndexOf('/')
-        let uuid = connectionInfo.secret_ref.substr(uuidIndex + 1)
-        newEndpoint = postResponse.data.endpoint
-
-        return this.getSecretPayload(uuid)
-      }).then(conInfoResponse => {
+      })
+
+      connectionInfo = { secret_ref: response.data.secret_ref }
+      let newPayload = {
+        endpoint: {
+          name: parsedEndpoint.name,
+          description: parsedEndpoint.description,
+          type: endpoint.type,
+          connection_info: connectionInfo,
+        },
+      }
+      let postResponse = await Api.send({
+        url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
+        method: 'POST',
+        data: newPayload,
+      })
+
+      let uuidIndex = connectionInfo.secret_ref.lastIndexOf('/')
+      let uuid = connectionInfo.secret_ref.substr(uuidIndex + 1)
+      newEndpoint = postResponse.data.endpoint
+
+      try {
+        let conInfoResponse = await this.getSecretPayload(uuid)
         newEndpoint.connection_info = {
         newEndpoint.connection_info = {
           ...newEndpoint.connection_info,
           ...newEndpoint.connection_info,
           ...conInfoResponse.data,
           ...conInfoResponse.data,
         }
         }
         return newEndpoint
         return newEndpoint
-      }).catch(e => {
+      } catch (e) {
         if (e.secretCustomError) {
         if (e.secretCustomError) {
           notificationStore.alert(e.secretCustomError, 'error')
           notificationStore.alert(e.secretCustomError, 'error')
         }
         }
         throw e
         throw e
-      })
+      }
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints`,
       method: 'POST',
       method: 'POST',
       data: {
       data: {
@@ -254,17 +257,15 @@ class EdnpointSource {
           type: endpoint.type,
           type: endpoint.type,
         },
         },
       },
       },
-    }).then(response => {
-      return SchemaParser.parseConnectionResponse(response.data.endpoint)
     })
     })
+    return SchemaParser.parseConnectionResponse(response.data.endpoint)
   }
   }
 
 
-  static loadStorage(endpointId: string, data: any): Promise<Storage> {
+  async loadStorage(endpointId: string, data: any): Promise<Storage> {
     let env = btoa(JSON.stringify(data))
     let env = btoa(JSON.stringify(data))
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/storage?env=${env}`).then(response => {
-      return response.data.storage
-    })
+    let response = await Api.get(`${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/storage?env=${env}`)
+    return response.data.storage
   }
   }
 }
 }
 
 
-export default EdnpointSource
+export default new EndpointSource()

+ 11 - 14
src/sources/InstanceSource.js

@@ -20,7 +20,7 @@ import type { Instance } from '../types/Instance'
 import { servicesUrl } from '../constants'
 import { servicesUrl } from '../constants'
 
 
 class InstanceSource {
 class InstanceSource {
-  static loadInstancesChunk(
+  async loadInstancesChunk(
     endpointId: string,
     endpointId: string,
     chunkSize: number,
     chunkSize: number,
     lastInstanceId?: string,
     lastInstanceId?: string,
@@ -53,32 +53,29 @@ class InstanceSource {
     let keys = Object.keys(queryParams)
     let keys = Object.keys(queryParams)
     url = `${url}${keys.length > 0 ? '?' : ''}${keys.map(p => `${p}=${queryParams[p]}`).join('&')}`
     url = `${url}${keys.length > 0 ? '?' : ''}${keys.map(p => `${p}=${queryParams[p]}`).join('&')}`
 
 
-    return Api.send({ url, cancelId }).then(response => {
-      return response.data.instances
-    })
+    let response = await Api.send({ url, cancelId })
+    return response.data.instances
   }
   }
 
 
-  static loadInstances(endpointId: string): Promise<Instance[]> {
+  async loadInstances(endpointId: string): Promise<Instance[]> {
     Api.cancelRequests(endpointId)
     Api.cancelRequests(endpointId)
     let url = `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances`
     let url = `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances`
-    return Api.send({ url, cancelId: endpointId }).then(response => {
-      return response.data.instances
-    })
+    let response = await Api.send({ url, cancelId: endpointId })
+    return response.data.instances
   }
   }
 
 
-  static loadInstanceDetails(endpointId: string, instanceName: string, reqId: number, quietError?: boolean): Promise<{ instance: Instance, reqId: number }> {
-    return Api.send({
+  async loadInstanceDetails(endpointId: string, instanceName: string, reqId: number, quietError?: boolean): Promise<{ instance: Instance, reqId: number }> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances/${btoa(instanceName)}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances/${btoa(instanceName)}`,
       cancelId: `instanceDetail-${reqId}`,
       cancelId: `instanceDetail-${reqId}`,
       quietError,
       quietError,
-    }).then(response => {
-      return { instance: response.data.instance, reqId }
     })
     })
+    return { instance: response.data.instance, reqId }
   }
   }
 
 
-  static cancelInstancesDetailsRequests(reqId: number) {
+  cancelInstancesDetailsRequests(reqId: number) {
     Api.cancelRequests(`instanceDetail-${reqId}`)
     Api.cancelRequests(`instanceDetail-${reqId}`)
   }
   }
 }
 }
 
 
-export default InstanceSource
+export default new InstanceSource()

+ 27 - 25
src/sources/MigrationSource.js

@@ -51,29 +51,27 @@ class MigrationSourceUtils {
 }
 }
 
 
 class MigrationSource {
 class MigrationSource {
-  static getMigrations(skipLog?: boolean): Promise<MainItem[]> {
-    return Api.send({
+  async getMigrations(skipLog?: boolean): Promise<MainItem[]> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/detail`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/detail`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let migrations = response.data.migrations
-      MigrationSourceUtils.sortMigrations(migrations)
-      return migrations
     })
     })
+    let migrations = response.data.migrations
+    MigrationSourceUtils.sortMigrations(migrations)
+    return migrations
   }
   }
 
 
-  static getMigration(migrationId: string, skipLog?: boolean): Promise<MainItem> {
-    return Api.send({
+  async getMigration(migrationId: string, skipLog?: boolean): Promise<MainItem> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let migration = response.data.migration
-      sortTasks(migration.tasks, MigrationSourceUtils.sortTaskUpdates)
-      return migration
     })
     })
+    let migration = response.data.migration
+    sortTasks(migration.tasks, MigrationSourceUtils.sortTaskUpdates)
+    return migration
   }
   }
 
 
-  static recreate(opts: {
+  async recreate(opts: {
     sourceEndpoint: Endpoint,
     sourceEndpoint: Endpoint,
     destEndpoint: Endpoint,
     destEndpoint: Endpoint,
     instanceNames: string[],
     instanceNames: string[],
@@ -132,29 +130,32 @@ class MigrationSource {
       }
       }
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then(response => response.data.migration)
+    })
+    return response.data.migration
   }
   }
 
 
-  static cancel(migrationId: string): Promise<string> {
-    return Api.send({
+  async cancel(migrationId: string): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}/actions`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}/actions`,
       method: 'POST',
       method: 'POST',
       data: { cancel: null },
       data: { cancel: null },
-    }).then(() => migrationId)
+    })
+    return migrationId
   }
   }
 
 
-  static delete(migrationId: string): Promise<string> {
-    return Api.send({
+  async delete(migrationId: string): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => migrationId)
+    })
+    return migrationId
   }
   }
 
 
-  static migrateReplica(replicaId: string, options: Field[]): Promise<MainItem> {
+  async migrateReplica(replicaId: string, options: Field[]): Promise<MainItem> {
     let payload = {
     let payload = {
       migration: {
       migration: {
         replica_id: replicaId,
         replica_id: replicaId,
@@ -164,13 +165,14 @@ class MigrationSource {
       payload.migration[o.name] = o.value || false
       payload.migration[o.name] = o.value || false
     })
     })
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then(response => response.data.migration)
+    })
+    return response.data.migration
   }
   }
 }
 }
 
 
-export default MigrationSource
+export default new MigrationSource()
 
 

+ 6 - 7
src/sources/NetworkSource.js

@@ -20,19 +20,18 @@ import type { Network } from '../types/Network'
 import { servicesUrl } from '../constants'
 import { servicesUrl } from '../constants'
 
 
 class NetworkSource {
 class NetworkSource {
-  static loadNetworks(enpointId: string, environment: ?{ [string]: mixed }, options?: {
+  async loadNetworks(enpointId: string, environment: ?{ [string]: mixed }, options?: {
     quietError?: boolean,
     quietError?: boolean,
   }): Promise<Network[]> {
   }): Promise<Network[]> {
     let url = `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${enpointId}/networks`
     let url = `${servicesUrl.coriolis}/${Api.projectId}/endpoints/${enpointId}/networks`
     if (environment) {
     if (environment) {
       url = `${url}?env=${btoa(JSON.stringify(environment))}`
       url = `${url}?env=${btoa(JSON.stringify(environment))}`
     }
     }
-    return Api.send({ url, quietError: options && options.quietError }).then(response => {
-      let networks = response.data.networks.filter(n => n.name.indexOf('coriolis-migrnet') === -1)
-      networks.sort((a, b) => a.name.localeCompare(b.name))
-      return networks
-    })
+    let response = await Api.send({ url, quietError: options && options.quietError })
+    let networks = response.data.networks.filter(n => n.name.indexOf('coriolis-migrnet') === -1)
+    networks.sort((a, b) => a.name.localeCompare(b.name))
+    return networks
   }
   }
 }
 }
 
 
-export default NetworkSource
+export default new NetworkSource()

+ 38 - 38
src/sources/NotificationSource.js

@@ -113,52 +113,52 @@ class DataUtils {
 }
 }
 
 
 class NotificationSource {
 class NotificationSource {
-  static loadData(): Promise<NotificationItemData[]> {
-    return Promise.all([
+  async loadData(): Promise<NotificationItemData[]> {
+    let [migrationsResponse, replicasResponse] = await Promise.all([
       Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`, skipLog: true, quietError: true }),
       Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`, skipLog: true, quietError: true }),
       Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`, skipLog: true, quietError: true }),
       Api.send({ url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`, skipLog: true, quietError: true }),
-    ]).then(([migrationsResponse, replicasResponse]) => {
-      let migrations = migrationsResponse.data.migrations
-      let replicas = replicasResponse.data.replicas
-      let apiData = [...migrations, ...replicas]
-      apiData.sort((a, b) => moment(DataUtils.getUpdatedAt(b)).diff(DataUtils.getUpdatedAt(a)))
-
-      let notificationItems: NotificationItemData[] = apiData.map(item => {
-        let mainInfo = DataUtils.getMainInfo(item)
-
-        let newItem: NotificationItemData = {
-          id: item.id,
-          status: mainInfo.status,
-          type: item.type,
-          name: item.instances[0],
-          updatedAt: mainInfo.updated_at,
-          description: DataUtils.getItemDescription(item),
-        }
-        return newItem
-      }).filter(item => item.status).filter((item, i) => i < 10)
-
-      let storageData = NotificationStorage.loadSeen()
-      if (!storageData) {
-        NotificationStorage.saveSeen(notificationItems)
-        storageData = NotificationStorage.loadSeen() || []
+    ])
+
+    let migrations = migrationsResponse.data.migrations
+    let replicas = replicasResponse.data.replicas
+    let apiData = [...migrations, ...replicas]
+    apiData.sort((a, b) => moment(DataUtils.getUpdatedAt(b)).diff(DataUtils.getUpdatedAt(a)))
+
+    let notificationItems: NotificationItemData[] = apiData.map(item => {
+      let mainInfo = DataUtils.getMainInfo(item)
+
+      let newItem: NotificationItemData = {
+        id: item.id,
+        status: mainInfo.status,
+        type: item.type,
+        name: item.instances[0],
+        updatedAt: mainInfo.updated_at,
+        description: DataUtils.getItemDescription(item),
       }
       }
-      notificationItems.forEach(item => {
-        item.unseen = true
-        // $FlowIgnore
-        storageData.forEach(storageItem => {
-          if (storageItem.id === item.id && storageItem.status === item.status && storageItem.updatedAt === item.updatedAt) {
-            item.unseen = false
-          }
-        })
+      return newItem
+    }).filter(item => item.status).filter((item, i) => i < 10)
+
+    let storageData = NotificationStorage.loadSeen()
+    if (!storageData) {
+      NotificationStorage.saveSeen(notificationItems)
+      storageData = NotificationStorage.loadSeen() || []
+    }
+    notificationItems.forEach(item => {
+      item.unseen = true
+      // $FlowIgnore
+      storageData.forEach(storageItem => {
+        if (storageItem.id === item.id && storageItem.status === item.status && storageItem.updatedAt === item.updatedAt) {
+          item.unseen = false
+        }
       })
       })
-      NotificationStorage.clean(notificationItems)
-      return notificationItems
     })
     })
+    NotificationStorage.clean(notificationItems)
+    return notificationItems
   }
   }
 
 
-  static saveSeen(notificationItems: NotificationItemData[]) {
+  saveSeen(notificationItems: NotificationItemData[]) {
     NotificationStorage.saveSeen(notificationItems)
     NotificationStorage.saveSeen(notificationItems)
   }
   }
 }
 }
 
 
-export default NotificationSource
+export default new NotificationSource()

+ 52 - 58
src/sources/ProjectSource.js

@@ -22,73 +22,70 @@ import type { Project, Role, RoleAssignment } from '../types/Project'
 import type { User } from '../types/User'
 import type { User } from '../types/User'
 
 
 class ProjectsSource {
 class ProjectsSource {
-  static getProjects(skipLog?: boolean): Promise<Project[]> {
-    return Api.send({
+  async getProjects(skipLog?: boolean): Promise<Project[]> {
+    let response = await Api.send({
       url: servicesUrl.projects,
       url: servicesUrl.projects,
       skipLog,
       skipLog,
-    }).then((response) => {
-      if (response.data.projects) {
-        let projects: Project[] = response.data.projects
-        projects.sort((a, b) => a.name.localeCompare(b.name))
-        return projects
-      }
-      return []
     })
     })
+    if (response.data.projects) {
+      let projects: Project[] = response.data.projects
+      projects.sort((a, b) => a.name.localeCompare(b.name))
+      return projects
+    }
+    return []
   }
   }
 
 
-  static getProjectDetails(projectId: string): Promise<Project> {
-    return Api.get(`${coriolisUrl}identity/projects/${projectId}`).then(response => {
-      return response.data.project
-    })
+  async getProjectDetails(projectId: string): Promise<Project> {
+    let response = await Api.get(`${coriolisUrl}identity/projects/${projectId}`)
+    return response.data.project
   }
   }
 
 
-  static getRoleAssignments(skipLog?: boolean): Promise<RoleAssignment[]> {
-    return Api.send({
+  async getRoleAssignments(skipLog?: boolean): Promise<RoleAssignment[]> {
+    let response = await Api.send({
       url: `${coriolisUrl}identity/role_assignments?include_names`,
       url: `${coriolisUrl}identity/role_assignments?include_names`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let assignments: RoleAssignment[] = response.data.role_assignments
-      assignments.sort((a1, a2) => a1.role.name.localeCompare(a2.role.name))
-      return assignments
     })
     })
+    let assignments: RoleAssignment[] = response.data.role_assignments
+    assignments.sort((a1, a2) => a1.role.name.localeCompare(a2.role.name))
+    return assignments
   }
   }
 
 
-  static getUsers(projectId: string): Promise<User[]> {
-    return this.getRoleAssignments().then(assignments => {
-      const userIds: string[] = assignments
-        .filter(a => a.scope.project.id === projectId)
-        .filter((a, i, arr) => arr.findIndex(e => a.user.id === e.user.id) === i)
-        .map(a => a.user.id)
-      return Promise.all(userIds.map(id => {
-        return UserSource.getUserInfo(id)
-      })).then((users: User[]) => {
-        users.sort((a, b) => a.name.localeCompare(b.name))
-        return users
-      })
-    })
+  async getUsers(projectId: string): Promise<User[]> {
+    let assignments = await this.getRoleAssignments()
+    const userIds: string[] = assignments
+      .filter(a => a.scope.project.id === projectId)
+      .filter((a, i, arr) => arr.findIndex(e => a.user.id === e.user.id) === i)
+      .map(a => a.user.id)
+    let users: User[] = await Promise.all(userIds.map(async id => {
+      let user: User = await UserSource.getUserInfo(id)
+      return user
+    }))
+    users.sort((a, b) => a.name.localeCompare(b.name))
+    return users
   }
   }
 
 
-  static removeUser(projectId: string, userId: string, roleIds: string[]): Promise<void> {
-    return Promise.all(roleIds.map(id => {
-      return Api.send({
+  async removeUser(projectId: string, userId: string, roleIds: string[]): Promise<void> {
+    await Promise.all(roleIds.map(async id => {
+      await Api.send({
         url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${id}`,
         url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${id}`,
         method: 'DELETE',
         method: 'DELETE',
       })
       })
-    })).then(() => { })
+    }))
   }
   }
 
 
-  static assignUser(projectId: string, userId: string, roleId: string): Promise<void> {
-    return Api.send({
+  async assignUser(projectId: string, userId: string, roleId: string): Promise<void> {
+    await Api.send({
       url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${roleId}`,
       url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${roleId}`,
       method: 'PUT',
       method: 'PUT',
-    }).then(() => { })
+    })
   }
   }
 
 
-  static getRoles(): Promise<Role[]> {
-    return UserSource.getRoles()
+  async getRoles(): Promise<Role[]> {
+    let roles: Role[] = await UserSource.getRoles()
+    return roles
   }
   }
 
 
-  static update(projectId: string, project: Project): Promise<Project> {
+  async update(projectId: string, project: Project): Promise<Project> {
     let data = { project: {} }
     let data = { project: {} }
     if (project.name != null) {
     if (project.name != null) {
       data.project.name = project.name
       data.project.name = project.name
@@ -100,21 +97,22 @@ class ProjectsSource {
       data.project.enabled = project.enabled
       data.project.enabled = project.enabled
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${coriolisUrl}identity/projects/${projectId}`,
       url: `${coriolisUrl}identity/projects/${projectId}`,
       method: 'PATCH',
       method: 'PATCH',
       data,
       data,
-    }).then(response => response.data.project)
+    })
+    return response.data.project
   }
   }
 
 
-  static delete(projectId: string): Promise<void> {
-    return Api.send({
+  async delete(projectId: string): Promise<void> {
+    await Api.send({
       url: `${coriolisUrl}identity/projects/${projectId}`,
       url: `${coriolisUrl}identity/projects/${projectId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => { })
+    })
   }
   }
 
 
-  static add(project: Project, userId: string): Promise<Project> {
+  async add(project: Project, userId: string): Promise<Project> {
     let data = { project: {} }
     let data = { project: {} }
 
 
     data.project.name = project.name
     data.project.name = project.name
@@ -124,20 +122,16 @@ class ProjectsSource {
     if (project.description != null) {
     if (project.description != null) {
       data.project.description = project.description
       data.project.description = project.description
     }
     }
-    let addedProject: Project
-    return Api.send({
+    let response = await Api.send({
       url: `${coriolisUrl}identity/projects/`,
       url: `${coriolisUrl}identity/projects/`,
       method: 'POST',
       method: 'POST',
       data,
       data,
-    }).then(response => {
-      addedProject = response.data.project
-      return UserSource.getAdminRoleId()
-    }).then(adminRoleId => {
-      return UserSource.assignUserToProjectWithRole(userId, addedProject.id, adminRoleId)
-    }).then(() => {
-      return addedProject
     })
     })
+    let addedProject: Project = response.data.project
+    let adminRoleId: string = await UserSource.getAdminRoleId()
+    await UserSource.assignUserToProjectWithRole(userId, addedProject.id, adminRoleId)
+    return addedProject
   }
   }
 }
 }
 
 
-export default ProjectsSource
+export default new ProjectsSource()

+ 21 - 29
src/sources/ProviderSource.js

@@ -22,39 +22,31 @@ import type { Providers } from '../types/Providers'
 import type { OptionValues } from '../types/Endpoint'
 import type { OptionValues } from '../types/Endpoint'
 
 
 class ProviderSource {
 class ProviderSource {
-  static getConnectionInfoSchema(providerName: string): Promise<Field[]> {
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${providerTypes.CONNECTION}`).then(response => {
-      let schema = response.data.schemas.connection_info_schema
-      schema = SchemaParser.connectionSchemaToFields(providerName, schema)
-      return schema
-    })
+  async getConnectionInfoSchema(providerName: string): Promise<Field[]> {
+    let response = await Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${providerTypes.CONNECTION}`)
+    let schema = response.data.schemas.connection_info_schema
+    schema = SchemaParser.connectionSchemaToFields(providerName, schema)
+    return schema
   }
   }
 
 
-  static loadProviders(): Promise<Providers> {
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers`).then(response => response.data.providers)
+  async loadProviders(): Promise<Providers> {
+    let response = await Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers`)
+    return response.data.providers
   }
   }
 
 
-  static loadDestinationSchema(providerName: string, schemaType: string): Promise<Field[]> {
-    let schemaTypeInt = schemaType === 'migration' ? providerTypes.TARGET_MIGRATION : providerTypes.TARGET_REPLICA
+  async loadOptionsSchema(providerName: string, schemaType: 'migration' | 'replica', optionsType: 'source' | 'destination'): Promise<Field[]> {
+    let schemaTypeInt = schemaType === 'migration' ?
+      optionsType === 'source' ? providerTypes.SOURCE_MIGRATION : providerTypes.TARGET_MIGRATION :
+      optionsType === 'source' ? providerTypes.SOURCE_REPLICA : providerTypes.TARGET_REPLICA
 
 
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${schemaTypeInt}`).then(response => {
-      let schema = response.data.schemas.destination_environment_schema
-      let fields = SchemaParser.optionsSchemaToFields(providerName, schema)
-      return fields
-    })
+    let response = await Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${schemaTypeInt}`)
+    let schema = optionsType === 'source' ?
+      { oneOf: [response.data.schemas.source_environment_schema] } : response.data.schemas.destination_environment_schema
+    let fields = SchemaParser.optionsSchemaToFields(providerName, schema)
+    return fields
   }
   }
 
 
-  static loadSourceSchema(providerName: string, schemaType: string): Promise<Field[]> {
-    let schemaTypeInt = schemaType === 'replica' ? providerTypes.SOURCE_REPLICA : providerTypes.SOURCE_MIGRATION
-
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${schemaTypeInt}`).then(response => {
-      let schema = { oneOf: [response.data.schemas.source_environment_schema] }
-      let fields = SchemaParser.optionsSchemaToFields(providerName, schema)
-      return fields
-    })
-  }
-
-  static getOptionsValues(optionsType: 'source' | 'destination', endpointId: string, envData: ?{ [string]: mixed }): Promise<OptionValues[]> {
+  async getOptionsValues(optionsType: 'source' | 'destination', endpointId: string, envData: ?{ [string]: mixed }): Promise<OptionValues[]> {
     let envString = ''
     let envString = ''
     if (envData) {
     if (envData) {
       envString = `?env=${btoa(JSON.stringify(envData))}`
       envString = `?env=${btoa(JSON.stringify(envData))}`
@@ -62,9 +54,9 @@ class ProviderSource {
     let callName = optionsType === 'source' ? 'source-options' : 'destination-options'
     let callName = optionsType === 'source' ? 'source-options' : 'destination-options'
     let fieldName = optionsType === 'source' ? 'source_options' : 'destination_options'
     let fieldName = optionsType === 'source' ? 'source_options' : 'destination_options'
 
 
-    return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/${callName}${envString}`)
-      .then(response => response.data[fieldName])
+    let response = await Api.get(`${servicesUrl.coriolis}/${Api.projectId}/endpoints/${endpointId}/${callName}${envString}`)
+    return response.data[fieldName]
   }
   }
 }
 }
 
 
-export default ProviderSource
+export default new ProviderSource()

+ 44 - 43
src/sources/ReplicaSource.js

@@ -119,91 +119,91 @@ class ReplicaSourceUtils {
 }
 }
 
 
 class ReplicaSource {
 class ReplicaSource {
-  static getReplicas(skipLog?: boolean): Promise<MainItem[]> {
-    return Api.send({
+  async getReplicas(skipLog?: boolean): Promise<MainItem[]> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let replicas = response.data.replicas
-      replicas = ReplicaSourceUtils.filterDeletedExecutionsInReplicas(replicas)
-      ReplicaSourceUtils.sortReplicas(replicas)
-      return replicas
     })
     })
+    let replicas = response.data.replicas
+    replicas = ReplicaSourceUtils.filterDeletedExecutionsInReplicas(replicas)
+    ReplicaSourceUtils.sortReplicas(replicas)
+    return replicas
   }
   }
 
 
-  static getReplicaExecutions(replicaId: string, skipLog?: boolean): Promise<Execution[]> {
-    return Api.send({
+  async getReplicaExecutions(replicaId: string, skipLog?: boolean): Promise<Execution[]> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/detail`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/detail`,
       skipLog,
       skipLog,
-    }).then((response) => {
-      let executions = response.data.executions
-      ReplicaSourceUtils.sortExecutionsAndTasks(executions)
-
-      return executions
     })
     })
+    let executions = response.data.executions
+    ReplicaSourceUtils.sortExecutionsAndTasks(executions)
+
+    return executions
   }
   }
 
 
-  static getReplica(replicaId: string, skipLog?: boolean): Promise<MainItem> {
-    return Api.send({
+  async getReplica(replicaId: string, skipLog?: boolean): Promise<MainItem> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`,
       skipLog,
       skipLog,
-    }).then(response => {
-      let replica = response.data.replica
-      replica.executions = ReplicaSourceUtils.filterDeletedExecutions(replica.executions)
-      ReplicaSourceUtils.sortExecutions(replica.executions)
-      return replica
     })
     })
+    let replica = response.data.replica
+    replica.executions = ReplicaSourceUtils.filterDeletedExecutions(replica.executions)
+    ReplicaSourceUtils.sortExecutions(replica.executions)
+    return replica
   }
   }
 
 
-  static execute(replicaId: string, fields?: Field[]): Promise<Execution> {
+  async execute(replicaId: string, fields?: Field[]): Promise<Execution> {
     let payload = { execution: { shutdown_instances: false } }
     let payload = { execution: { shutdown_instances: false } }
     if (fields) {
     if (fields) {
       fields.forEach(f => {
       fields.forEach(f => {
         payload.execution[f.name] = f.value || false
         payload.execution[f.name] = f.value || false
       })
       })
     }
     }
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then((response) => {
-      let execution = response.data.execution
-      sortTasks(execution.tasks, ReplicaSourceUtils.sortTaskUpdates)
-      return execution
     })
     })
+    let execution = response.data.execution
+    sortTasks(execution.tasks, ReplicaSourceUtils.sortTaskUpdates)
+    return execution
   }
   }
 
 
-  static cancelExecution(replicaId: string, executionId: string): Promise<string> {
-    return Api.send({
+  async cancelExecution(replicaId: string, executionId: string): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}/actions`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}/actions`,
       method: 'POST',
       method: 'POST',
       data: { cancel: null },
       data: { cancel: null },
-    }).then(() => replicaId)
+    })
+    return replicaId
   }
   }
 
 
-  static deleteExecution(replicaId: string, executionId: string): Promise<string> {
-    return Api.send({
+  async deleteExecution(replicaId: string, executionId: string): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => replicaId)
+    })
+    return replicaId
   }
   }
 
 
-  static delete(replicaId: string): Promise<string> {
-    return Api.send({
+  async delete(replicaId: string): Promise<string> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => replicaId)
+    })
+    return replicaId
   }
   }
 
 
-  static deleteDisks(replicaId: string): Promise<Execution> {
-    return Api.send({
+  async deleteDisks(replicaId: string): Promise<Execution> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/actions`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/actions`,
       method: 'POST',
       method: 'POST',
       data: { 'delete-disks': null },
       data: { 'delete-disks': null },
-    }).then(response => response.data.execution)
+    })
+    return response.data.execution
   }
   }
 
 
-  static update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string): Promise<Execution> {
+  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string): Promise<Execution> {
     const parser = OptionsSchemaPlugin[destinationEndpoint.type] || OptionsSchemaPlugin.default
     const parser = OptionsSchemaPlugin[destinationEndpoint.type] || OptionsSchemaPlugin.default
     let payload = { replica: {} }
     let payload = { replica: {} }
 
 
@@ -228,13 +228,14 @@ class ReplicaSource {
       payload.replica.storage_mappings = parser.getStorageMap(defaultStorage, updateData.storage, storageConfigDefault)
       payload.replica.storage_mappings = parser.getStorageMap(defaultStorage, updateData.storage, storageConfigDefault)
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replica.id}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replica.id}`,
       method: 'PUT',
       method: 'PUT',
       data: payload,
       data: payload,
-    }).then(response => response.data)
+    })
+    return response.data
   }
   }
 }
 }
 
 
-export default ReplicaSource
+export default new ReplicaSource()
 
 

+ 40 - 38
src/sources/ScheduleSource.js

@@ -22,7 +22,7 @@ import DateUtils from '../utils/DateUtils'
 import type { Schedule } from '../types/Schedule'
 import type { Schedule } from '../types/Schedule'
 
 
 class ScheduleSource {
 class ScheduleSource {
-  static scheduleSinge(replicaId: string, scheduleData: Schedule): Promise<Schedule> {
+  async scheduleSinge(replicaId: string, scheduleData: Schedule): Promise<Schedule> {
     let payload = {
     let payload = {
       schedule: {},
       schedule: {},
       expiration_date: null,
       expiration_date: null,
@@ -43,39 +43,41 @@ class ScheduleSource {
       })
       })
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then(response => response.data.schedule)
+    })
+    return response.data.schedule
   }
   }
 
 
-  static scheduleMultiple(replicaId: string, schedules: Schedule[]): Promise<Schedule[]> {
-    return Promise.all(schedules.map(schedule => {
-      return ScheduleSource.scheduleSinge(replicaId, schedule)
+  async scheduleMultiple(replicaId: string, schedules: Schedule[]): Promise<Schedule[]> {
+    let scheduledSchedules: Schedule[] = await Promise.all(schedules.map(async schedule => {
+      let scheduledSchedule: Schedule = await this.scheduleSinge(replicaId, schedule)
+      return scheduledSchedule
     }))
     }))
+    return scheduledSchedules
   }
   }
 
 
-  static getSchedules(replicaId: string, opts?: { skipLog?: boolean }): Promise<Schedule[]> {
-    return Api.send({
+  async getSchedules(replicaId: string, opts?: { skipLog?: boolean }): Promise<Schedule[]> {
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       skipLog: opts && opts.skipLog,
       skipLog: opts && opts.skipLog,
-    }).then(response => {
-      let schedules = [...response.data.schedules]
-      schedules.forEach(s => {
-        if (s.expiration_date) {
-          s.expiration_date = DateUtils.getLocalTime(s.expiration_date)
-        }
-        if (s.shutdown_instance) {
-          s.shutdown_instances = s.shutdown_instance
-        }
-      })
-      schedules.sort((a, b) => moment(a.created_at).diff(b.created_at))
-      return schedules
     })
     })
+    let schedules = [...response.data.schedules]
+    schedules.forEach(s => {
+      if (s.expiration_date) {
+        s.expiration_date = DateUtils.getLocalTime(s.expiration_date)
+      }
+      if (s.shutdown_instance) {
+        s.shutdown_instances = s.shutdown_instance
+      }
+    })
+    schedules.sort((a, b) => moment(a.created_at).diff(b.created_at))
+    return schedules
   }
   }
 
 
-  static addSchedule(replicaId: string, schedule: Schedule): Promise<Schedule> {
+  async addSchedule(replicaId: string, schedule: Schedule): Promise<Schedule> {
     let payload = {
     let payload = {
       schedule: { hour: 0, minute: 0 },
       schedule: { hour: 0, minute: 0 },
       enabled: false,
       enabled: false,
@@ -84,21 +86,22 @@ class ScheduleSource {
       payload.schedule = { ...schedule.schedule }
       payload.schedule = { ...schedule.schedule }
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then(response => response.data.schedule)
+    })
+    return response.data.schedule
   }
   }
 
 
-  static removeSchedule(replicaId: string, scheduleId: string): Promise<void> {
-    return Api.send({
+  async removeSchedule(replicaId: string, scheduleId: string): Promise<void> {
+    await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => { })
+    })
   }
   }
 
 
-  static updateSchedule(
+  async updateSchedule(
     replicaId: string,
     replicaId: string,
     scheduleId: string,
     scheduleId: string,
     scheduleData: Schedule,
     scheduleData: Schedule,
@@ -128,21 +131,20 @@ class ScheduleSource {
       })
       })
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
       method: 'PUT',
       method: 'PUT',
       data: payload,
       data: payload,
-    }).then(response => {
-      let s = { ...response.data.schedule }
-      if (s.expiration_date) {
-        s.expiration_date = DateUtils.getLocalTime(s.expiration_date)
-      }
-      if (s.shutdown_instance) {
-        s.shutdown_instances = s.shutdown_instance
-      }
-      return s
     })
     })
+    let s = { ...response.data.schedule }
+    if (s.expiration_date) {
+      s.expiration_date = DateUtils.getLocalTime(s.expiration_date)
+    }
+    if (s.shutdown_instance) {
+      s.shutdown_instances = s.shutdown_instance
+    }
+    return s
   }
   }
 }
 }
 
 
-export default ScheduleSource
+export default new ScheduleSource()

+ 124 - 140
src/sources/UserSource.js

@@ -37,15 +37,15 @@ class UserModel {
 }
 }
 
 
 class UserSource {
 class UserSource {
-  static saveDomainName(domainName: string) {
+  saveDomainName(domainName: string) {
     localStorage.setItem('userDomainName', domainName)
     localStorage.setItem('userDomainName', domainName)
   }
   }
 
 
-  static getDomainName(): string {
+  getDomainName(): string {
     return localStorage.getItem('userDomainName') || configLoader.config.defaultUserDomain
     return localStorage.getItem('userDomainName') || configLoader.config.defaultUserDomain
   }
   }
 
 
-  static login(userData: Credentials): Promise<User> {
+  async login(userData: Credentials): Promise<any> {
     let auth = {
     let auth = {
       auth: {
       auth: {
         identity: {
         identity: {
@@ -64,19 +64,18 @@ class UserSource {
 
 
     Api.setDefaultHeader('X-Auth-Token', null)
     Api.setDefaultHeader('X-Auth-Token', null)
 
 
-    return Api.send({
+    let response = await Api.send({
       url: servicesUrl.identity,
       url: servicesUrl.identity,
       method: 'POST',
       method: 'POST',
       data: auth,
       data: auth,
-    }).then(response => {
-      let token = response.headers ? response.headers['X-Subject-Token'] || response.headers['x-subject-token'] : ''
-      Api.setDefaultHeader('X-Auth-Token', token)
-      cookie.set('unscopedToken', token, { expires: 30 })
-      return response.data
     })
     })
+    let token = response.headers ? response.headers['X-Subject-Token'] || response.headers['x-subject-token'] : ''
+    Api.setDefaultHeader('X-Auth-Token', token)
+    cookie.set('unscopedToken', token, { expires: 30 })
+    return response.data
   }
   }
 
 
-  static loginScoped(projectId: string, skipCookie?: boolean): Promise<User> {
+  async loginScoped(projectId: string, skipCookie?: boolean): Promise<User> {
     let useProjectId = skipCookie ? projectId : cookie.get('projectId') || projectId
     let useProjectId = skipCookie ? projectId : cookie.get('projectId') || projectId
     let token = cookie.get('unscopedToken')
     let token = cookie.get('unscopedToken')
 
 
@@ -98,28 +97,30 @@ class UserSource {
 
 
     Api.setDefaultHeader('X-Auth-Token', null)
     Api.setDefaultHeader('X-Auth-Token', null)
 
 
-    return Api.send({
-      url: servicesUrl.identity,
-      method: 'POST',
-      data: auth,
-    }).then(response => {
+    try {
+      let response = await Api.send({
+        url: servicesUrl.identity,
+        method: 'POST',
+        data: auth,
+      })
       let token = response.headers ? response.headers['X-Subject-Token'] || response.headers['x-subject-token'] : ''
       let token = response.headers ? response.headers['X-Subject-Token'] || response.headers['x-subject-token'] : ''
-      let data = UserModel.parseUserData(response.data)
+      let data: User = UserModel.parseUserData(response.data)
       data = { ...data, token }
       data = { ...data, token }
       cookie.set('token', data.token, { expires: 30 })
       cookie.set('token', data.token, { expires: 30 })
       cookie.set('projectId', data.project.id, { expires: 30 })
       cookie.set('projectId', data.project.id, { expires: 30 })
       Api.setDefaultHeader('X-Auth-Token', data.token)
       Api.setDefaultHeader('X-Auth-Token', data.token)
 
 
       return data
       return data
-    }).catch(response => {
+    } catch (err) {
       if (!skipCookie) {
       if (!skipCookie) {
-        return UserSource.loginScoped(projectId, true)
+        let user: User = await this.loginScoped(projectId, true)
+        return user
       }
       }
-      return Promise.reject(response)
-    })
+      throw err
+    }
   }
   }
 
 
-  static tokenLogin(): Promise<User> {
+  async tokenLogin(): Promise<User> {
     let token = cookie.get('token')
     let token = cookie.get('token')
     let projectId = cookie.get('projectId')
     let projectId = cookie.get('projectId')
     if (token) {
     if (token) {
@@ -130,30 +131,31 @@ class UserSource {
       return Promise.reject()
       return Promise.reject()
     }
     }
 
 
-    return Api.send({
-      url: servicesUrl.identity,
-      headers: { 'X-Subject-Token': token },
-    }).then(response => {
+    try {
+      let response = await Api.send({
+        url: servicesUrl.identity,
+        headers: { 'X-Subject-Token': token },
+      })
       let data = UserModel.parseUserData(response.data)
       let data = UserModel.parseUserData(response.data)
       data = { ...data, token }
       data = { ...data, token }
       return data
       return data
-    }).catch(() => {
+    } catch (err) {
       cookie.remove('token')
       cookie.remove('token')
       Api.setDefaultHeader('X-Auth-Token', null)
       Api.setDefaultHeader('X-Auth-Token', null)
-      return Promise.reject()
-    })
+      throw err
+    }
   }
   }
 
 
-  static switchProject(): Promise<void> {
+  async switchProject(): Promise<void> {
     let token = cookie.get('unscopedToken')
     let token = cookie.get('unscopedToken')
     if (token) {
     if (token) {
       cookie.remove('projectId')
       cookie.remove('projectId')
-      return Promise.resolve()
+      return
     }
     }
-    return Promise.reject()
+    throw new Error()
   }
   }
 
 
-  static logout(): Promise<void> {
+  async logout(): Promise<void> {
     let token = cookie.get('token')
     let token = cookie.get('token')
     let clear = () => {
     let clear = () => {
       cookie.remove('token')
       cookie.remove('token')
@@ -161,36 +163,34 @@ class UserSource {
       Api.setDefaultHeader('X-Auth-Token', null)
       Api.setDefaultHeader('X-Auth-Token', null)
     }
     }
 
 
-    return Api.send({
-      url: servicesUrl.identity,
-      method: 'DELETE',
-      headers: { 'X-Subject-Token': token || '' },
-    }).then(() => {
-      clear()
-    }).catch(() => {
+    try {
+      await Api.send({
+        url: servicesUrl.identity,
+        method: 'DELETE',
+        headers: { 'X-Subject-Token': token || '' },
+      })
+    } catch (err) {
+      throw err
+    } finally {
       clear()
       clear()
-      return Promise.reject()
-    })
+    }
   }
   }
 
 
-  static getUserInfo(userId: string): Promise<User> {
-    return Api.get(`${servicesUrl.users}/${userId}`).then(response => response.data.user)
+  async getUserInfo(userId: string): Promise<User> {
+    let response = await Api.get(`${servicesUrl.users}/${userId}`)
+    return response.data.user
   }
   }
 
 
-  static getAllUsers(skipLog?: boolean): Promise<User[]> {
-    let users: User[] = []
-    return Api.send({ url: `${servicesUrl.users}`, skipLog })
-      .then(response => {
-        users = response.data.users
-        return utils.waitFor(() => Boolean(configLoader.config))
-      }).then(() => {
-        users = users.filter(u => !configLoader.config.hiddenUsers.find(hu => hu === u.name))
-          .sort((u1, u2) => u1.name.localeCompare(u2.name))
-        return users
-      })
+  async getAllUsers(skipLog?: boolean): Promise<User[]> {
+    let response = await Api.send({ url: `${servicesUrl.users}`, skipLog })
+    let users: User[] = response.data.users
+    await utils.waitFor(() => Boolean(configLoader.config))
+    users = users.filter(u => !configLoader.config.hiddenUsers.find(hu => hu === u.name))
+      .sort((u1, u2) => u1.name.localeCompare(u2.name))
+    return users
   }
   }
 
 
-  static update(userId: string, user: User, oldUser: ?User): Promise<User> {
+  async update(userId: string, user: User, oldUser: ?User): Promise<User> {
     const data = { user: {} }
     const data = { user: {} }
     let oldData = oldUser || {}
     let oldData = oldUser || {}
 
 
@@ -212,40 +212,34 @@ class UserSource {
     if (user.project_id || oldData.project_id) {
     if (user.project_id || oldData.project_id) {
       data.user.project_id = user.project_id
       data.user.project_id = user.project_id
     }
     }
-    let updatedUser: User
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.users}/${userId}`,
       url: `${servicesUrl.users}/${userId}`,
       method: 'PATCH',
       method: 'PATCH',
       data,
       data,
-    }).then(response => {
-      updatedUser = response.data.user
-      if (updatedUser.extra) {
-        updatedUser = {
-          ...updatedUser,
-          ...updatedUser.extra,
-        }
+    })
+    let updatedUser: User = response.data.user
+    if (updatedUser.extra) {
+      updatedUser = {
+        ...updatedUser,
+        ...updatedUser.extra,
       }
       }
-      return updatedUser
-    }).then(() => {
-      // if project id was updated, assign him to that project, if his not already assigned
-      if (data.user.project_id) {
-        return this.getProjects(updatedUser.id).then((projects: Project[]) => {
-          if (projects.find(p => p.id === data.user.project_id)) {
-            return updatedUser
-          }
-
-          return this.assignUserToProject(updatedUser.id, updatedUser.project_id || 'undefined').then(() => {
-            return updatedUser
-          })
-        })
+    }
+    // if project id was updated, assign him to that project, if his not already assigned
+    if (data.user.project_id) {
+      let projects: Project[] = await this.getProjects(updatedUser.id)
+      if (projects.find(p => p.id === data.user.project_id)) {
+        return updatedUser
       }
       }
 
 
+      await this.assignUserToProject(updatedUser.id, updatedUser.project_id || 'undefined')
       return updatedUser
       return updatedUser
-    })
+    }
+
+    return updatedUser
   }
   }
 
 
-  static add(user: User): Promise<User> {
+  async add(user: User): Promise<User> {
     let data = { user: {} }
     let data = { user: {} }
     data.user.name = user.name
     data.user.name = user.name
     data.user.password = user.password || ''
     data.user.password = user.password || ''
@@ -260,96 +254,86 @@ class UserSource {
     if (user.project_id) {
     if (user.project_id) {
       data.user.project_id = user.project_id
       data.user.project_id = user.project_id
     }
     }
-    let addedUser: User
-    return Api.send({
+
+    let response = await Api.send({
       url: `${servicesUrl.users}`,
       url: `${servicesUrl.users}`,
       method: 'POST',
       method: 'POST',
       data,
       data,
-    }).then(response => {
-      addedUser = response.data.user
-      if (addedUser.extra) {
-        addedUser = {
-          ...addedUser,
-          ...addedUser.extra,
-        }
-      }
-      return addedUser
-    }).then(() => {
-      // If the user has a project id set, assign him to that project with admin role
-      if (addedUser.project_id) {
-        return this.assignUserToProject(addedUser.id, addedUser.project_id || 'undefined').then(() => {
-          return addedUser
-        })
+    })
+    let addedUser: User = response.data.user
+    if (addedUser.extra) {
+      addedUser = {
+        ...addedUser,
+        ...addedUser.extra,
       }
       }
+    }
+    // If the user has a project id set, assign him to that project with admin role
+    if (addedUser.project_id) {
+      await this.assignUserToProject(addedUser.id, addedUser.project_id || 'undefined')
       return addedUser
       return addedUser
-    })
+    }
+    return addedUser
   }
   }
 
 
-  static delete(userId: string): Promise<void> {
-    return Api.send({
+  async delete(userId: string): Promise<void> {
+    await Api.send({
       url: `${coriolisUrl}identity/users/${userId}`,
       url: `${coriolisUrl}identity/users/${userId}`,
       method: 'DELETE',
       method: 'DELETE',
-    }).then(() => { })
+    })
   }
   }
 
 
-  static assignUserToProject(userId: string, projectId: string): Promise<void> {
-    return this.getMemberRoleId().then((roleId: string) => {
-      return this.assignUserToProjectWithRole(userId, projectId, roleId)
-    })
+  async assignUserToProject(userId: string, projectId: string): Promise<void> {
+    let roleId: string = await this.getMemberRoleId()
+    await this.assignUserToProjectWithRole(userId, projectId, roleId)
   }
   }
 
 
-  static assignUserToProjectWithRole(userId: string, projectId: string, roleId: string): Promise<void> {
-    return Api.send({
+  async assignUserToProjectWithRole(userId: string, projectId: string, roleId: string): Promise<void> {
+    await Api.send({
       url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${roleId}`,
       url: `${coriolisUrl}identity/projects/${projectId}/users/${userId}/roles/${roleId}`,
       method: 'PUT',
       method: 'PUT',
-    }).then(() => { })
+    })
   }
   }
 
 
-  static getMemberRoleId(): Promise<string> {
-    return this.getRoles().then((roles: { id: string, name: string }[]) => {
-      const role = roles.find(r => r.name === '_member_')
-      const roleId = role ? role.id : ''
-      return roleId
-    })
+  async getMemberRoleId(): Promise<string> {
+    let roles: { id: string, name: string }[] = await this.getRoles()
+    const role = roles.find(r => r.name === '_member_')
+    const roleId = role ? role.id : ''
+    return roleId
   }
   }
 
 
-  static getAdminRoleId(): Promise<string> {
-    return this.getRoles().then((roles: { id: string, name: string }[]) => {
-      const role = roles.find(r => r.name === 'admin')
-      const roleId = role ? role.id : ''
-      return roleId
-    })
+  async getAdminRoleId(): Promise<string> {
+    let roles: { id: string, name: string }[] = await this.getRoles()
+    const role = roles.find(r => r.name === 'admin')
+    const roleId = role ? role.id : ''
+    return roleId
   }
   }
 
 
-  static getRoles(): Promise<Role[]> {
-    return Api.get(`${coriolisUrl}identity/roles`).then(response => {
-      let roles: Role[] = response.data.roles
-      roles.sort((r1, r2) => r1.name.localeCompare(r2.name))
-      return roles
-    })
+  async getRoles(): Promise<Role[]> {
+    let response = await Api.get(`${coriolisUrl}identity/roles`)
+    let roles: Role[] = response.data.roles
+    roles.sort((r1, r2) => r1.name.localeCompare(r2.name))
+    return roles
   }
   }
 
 
-  static getProjects(userId: string): Promise<Project[]> {
-    return Api.get(`${coriolisUrl}identity/role_assignments?include_names`).then(response => {
-      let assignments: RoleAssignment[] = response.data.role_assignments
-      let projects: $Shape<Project>[] = assignments
-        .filter(a => a.user.id === userId)
-        .filter((a, i, arr) => arr.findIndex(e => e.scope.project.id === a.scope.project.id) === i)
-        .map(a => a.scope.project)
+  async getProjects(userId: string): Promise<Project[]> {
+    let response = await Api.get(`${coriolisUrl}identity/role_assignments?include_names`)
+    let assignments: RoleAssignment[] = response.data.role_assignments
+    let projects: $Shape<Project>[] = assignments
+      .filter(a => a.user.id === userId)
+      .filter((a, i, arr) => arr.findIndex(e => e.scope.project.id === a.scope.project.id) === i)
+      .map(a => a.scope.project)
 
 
-      return projects
-    })
+    return projects
   }
   }
 
 
-  static isAdmin(userId: string): Promise<boolean> {
-    return Api.send({
+  async isAdmin(userId: string): Promise<boolean> {
+    let response = await Api.send({
       url: `${coriolisUrl}identity/role_assignments?include_names`,
       url: `${coriolisUrl}identity/role_assignments?include_names`,
       quietError: true,
       quietError: true,
-    }).then(response => {
-      let roleAssignments: RoleAssignment[] = response.data.role_assignments
-      return roleAssignments.filter(a => a.user.id === userId).filter(a => a.role.name === 'admin').length > 0
     })
     })
+    let roleAssignments: RoleAssignment[] = response.data.role_assignments
+    return roleAssignments.filter(a => a.user.id === userId).filter(a => a.role.name === 'admin').length > 0
   }
   }
 }
 }
 
 
-export default UserSource
+export default new UserSource()

+ 17 - 13
src/sources/WizardSource.js

@@ -24,7 +24,7 @@ import type { StorageMap } from '../types/Endpoint'
 import type { MainItem } from '../types/MainItem'
 import type { MainItem } from '../types/MainItem'
 
 
 class WizardSource {
 class WizardSource {
-  static create(type: string, data: WizardData, storageMap: StorageMap[]): Promise<MainItem> {
+  async create(type: string, data: WizardData, storageMap: StorageMap[]): Promise<MainItem> {
     const sourceParser = data.source ? OptionsSchemaPlugin[data.source.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     const sourceParser = data.source ? OptionsSchemaPlugin[data.source.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     const destParser = data.target ? OptionsSchemaPlugin[data.target.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     const destParser = data.target ? OptionsSchemaPlugin[data.target.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     let payload = {}
     let payload = {}
@@ -47,29 +47,33 @@ class WizardSource {
       payload[type].source_environment = sourceParser.getDestinationEnv(data.sourceOptions)
       payload[type].source_environment = sourceParser.getDestinationEnv(data.sourceOptions)
     }
     }
 
 
-    return Api.send({
+    let response = await Api.send({
       url: `${servicesUrl.coriolis}/${Api.projectId}/${type}s`,
       url: `${servicesUrl.coriolis}/${Api.projectId}/${type}s`,
       method: 'POST',
       method: 'POST',
       data: payload,
       data: payload,
-    }).then(response => response.data[type])
+    })
+    return response.data[type]
   }
   }
 
 
-  static createMultiple(type: string, data: WizardData, storageMap: StorageMap[]): Promise<MainItem[]> {
+  async createMultiple(type: string, data: WizardData, storageMap: StorageMap[]): Promise<MainItem[]> {
     if (!data.selectedInstances) {
     if (!data.selectedInstances) {
-      return Promise.reject('No selected instances')
+      throw new Error('No selected instances')
     }
     }
-
-    return Promise.all(data.selectedInstances.map(instance => {
+    let mainItems = await Promise.all(data.selectedInstances.map(async instance => {
       let newData = { ...data }
       let newData = { ...data }
       newData.selectedInstances = [instance]
       newData.selectedInstances = [instance]
-      return WizardSource.create(type, newData, storageMap).catch(() => {
+      try {
+        let mainItem: MainItem = await this.create(type, newData, storageMap)
+        return mainItem
+      } catch (err) {
         notificationStore.alert(`Error while creating ${type} for instance ${instance.name}`, 'error')
         notificationStore.alert(`Error while creating ${type} for instance ${instance.name}`, 'error')
         return null
         return null
-      })
-    })).then(mainItems => mainItems.filter(Boolean).map(i => i))
+      }
+    }))
+    return mainItems.filter(Boolean).map(i => i)
   }
   }
 
 
-  static setPermalink(data: WizardData) {
+  setPermalink(data: WizardData) {
     // window.history.replaceState({}, null, `${window.location.href}?d=${btoa(JSON.stringify(data))}`)
     // window.history.replaceState({}, null, `${window.location.href}?d=${btoa(JSON.stringify(data))}`)
     let exp = /.*?(?:\?|$)/.exec(window.location.href)
     let exp = /.*?(?:\?|$)/.exec(window.location.href)
     if (!exp) {
     if (!exp) {
@@ -79,10 +83,10 @@ class WizardSource {
     window.history.replaceState({}, null, `${location}?d=${btoa(JSON.stringify(data))}`)
     window.history.replaceState({}, null, `${location}?d=${btoa(JSON.stringify(data))}`)
   }
   }
 
 
-  static getDataFromPermalink() {
+  getDataFromPermalink() {
     let dataExpExec = /\?d=(.*)/.exec(window.location.href)
     let dataExpExec = /\?d=(.*)/.exec(window.location.href)
     return dataExpExec && JSON.parse(atob(dataExpExec[1]))
     return dataExpExec && JSON.parse(atob(dataExpExec[1]))
   }
   }
 }
 }
 
 
-export default WizardSource
+export default new WizardSource()

+ 131 - 90
src/stores/EndpointStore.js

@@ -13,8 +13,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
 // @flow
 // @flow
-import { observable, action } from 'mobx'
-import type { Endpoint, Validation, StorageBackend } from '../types/Endpoint'
+import { observable, runInAction, action } from 'mobx'
+import type { Endpoint, Validation, StorageBackend, Storage } from '../types/Endpoint'
 import notificationStore from './NotificationStore'
 import notificationStore from './NotificationStore'
 import EndpointSource from '../sources/EndpointSource'
 import EndpointSource from '../sources/EndpointSource'
 
 
@@ -43,84 +43,100 @@ class EndpointStore {
   @observable storageLoading: boolean = false
   @observable storageLoading: boolean = false
   @observable storageConfigDefault: string = ''
   @observable storageConfigDefault: string = ''
 
 
-  @action getEndpoints(options?: { showLoading?: boolean, skipLog?: boolean }) {
+  @action async getEndpoints(options?: { showLoading?: boolean, skipLog?: boolean }) {
     if (options && options.showLoading) {
     if (options && options.showLoading) {
       this.loading = true
       this.loading = true
     }
     }
+    try {
+      let endpoints = await EndpointSource.getEndpoints(options && options.skipLog)
+      this.getEndpointsSuccess(endpoints)
+    } catch (ex) {
+      this.getEndpointsFailed()
+      throw ex
+    }
+  }
+
+  @action getEndpointsSuccess(endpoints: Endpoint[]) {
+    this.endpoints = endpoints
+    this.loading = false
+  }
 
 
-    return EndpointSource.getEndpoints(options && options.skipLog).then(endpoints => {
-      this.endpoints = endpoints
-      this.loading = false
-    }).catch(() => {
-      this.loading = false
-    })
+  @action getEndpointsFailed() {
+    this.loading = false
   }
   }
 
 
-  @action delete(endpoint: Endpoint) {
-    return EndpointSource.delete(endpoint).then(() => {
-      this.endpoints = this.endpoints.filter(e => e.id !== endpoint.id)
-    })
+  @action async delete(endpoint: Endpoint) {
+    await EndpointSource.delete(endpoint)
+    this.deleteSuccess(endpoint)
   }
   }
 
 
-  @action getConnectionInfo(endpoint: Endpoint) {
+  @action deleteSuccess(endpoint: Endpoint) {
+    this.endpoints = this.endpoints.filter(e => e.id !== endpoint.id)
+  }
+
+  @action async getConnectionInfo(endpoint: Endpoint) {
     this.connectionInfoLoading = true
     this.connectionInfoLoading = true
 
 
-    return EndpointSource.getConnectionInfo(endpoint).then(connectionInfo => {
+    try {
+      let connectionInfo = await EndpointSource.getConnectionInfo(endpoint)
       this.setConnectionInfo(connectionInfo)
       this.setConnectionInfo(connectionInfo)
-    }).catch(() => {
-      this.connectionInfoLoading = false
-      return Promise.reject()
-    })
+    } catch (ex) {
+      runInAction(() => { this.connectionInfoLoading = false })
+      throw ex
+    }
   }
   }
 
 
-  @action getConnectionsInfo(endpointsData: Endpoint[]): Promise<void> {
+  @action async getConnectionsInfo(endpointsData: Endpoint[]): Promise<void> {
     this.connectionsInfoLoading = true
     this.connectionsInfoLoading = true
-    return EndpointSource.getConnectionsInfo(endpointsData).then(endpoints => {
-      this.connectionsInfoLoading = false
-      this.connectionsInfo = endpoints
-    }).catch(() => {
-      this.connectionsInfoLoading = false
-    })
+    try {
+      let endpoints = await EndpointSource.getConnectionsInfo(endpointsData)
+      this.getConnectionsInfoSuccess(endpoints)
+    } catch (ex) {
+      runInAction(() => { this.connectionsInfoLoading = false })
+      throw ex
+    }
+  }
+
+  @action getConnectionsInfoSuccess(endpoints: Endpoint[]) {
+    this.connectionsInfoLoading = false
+    this.connectionsInfo = endpoints
   }
   }
 
 
-  @action duplicate(opts: {
+  async duplicate(opts: {
     shouldSwitchProject: boolean,
     shouldSwitchProject: boolean,
     onSwitchProject: () => Promise<void>,
     onSwitchProject: () => Promise<void>,
     endpoints: Endpoint[],
     endpoints: Endpoint[],
   }): Promise<void> {
   }): Promise<void> {
-    let endpoints = []
-    return Promise.all(opts.endpoints.map(endpoint => {
-      return EndpointSource.getConnectionInfo(endpoint).then(connectionInfo => {
-        endpoints.push({
+    try {
+      let endpoints: Endpoint[] = await Promise.all(opts.endpoints.map(async endpoint => {
+        let connectionInfo = await EndpointSource.getConnectionInfo(endpoint)
+        return {
           ...endpoint,
           ...endpoint,
           connection_info: connectionInfo,
           connection_info: connectionInfo,
           name: `${endpoint.name}${!opts.shouldSwitchProject ? ' (copy)' : ''}`,
           name: `${endpoint.name}${!opts.shouldSwitchProject ? ' (copy)' : ''}`,
-        })
-      })
-    })).then(() => {
+        }
+      }))
+
       if (opts.shouldSwitchProject) {
       if (opts.shouldSwitchProject) {
-        return opts.onSwitchProject()
+        await opts.onSwitchProject()
       }
       }
-      return Promise.resolve()
-    }).then(() => {
-      return Promise.all(endpoints.map(endpoint => {
-        return EndpointSource.add(endpoint, true)
-      }).map((p: Promise<any>) => p.catch(e => e)))
-        .then((results: (Endpoint | { status: string, data?: { description: string } })[]) => {
-          let internalServerErrors = results.filter(r => r.status && r.status === 500)
-          if (internalServerErrors.length > 0) {
-            notificationStore.alert(`There was a problem duplicating ${internalServerErrors.length} endpoint${internalServerErrors.length > 1 ? 's' : ''}`, 'error')
-          }
-          let forbiddenErrors = results.filter(r => r.status && r.status === 403)
-          if (forbiddenErrors.length > 0 && forbiddenErrors[0].data && forbiddenErrors[0].data.description) {
-            notificationStore.alert(String(forbiddenErrors[0].data.description), 'error')
-          }
-        })
-    }).catch(e => {
-      if (e.data && e.data.description) {
-        notificationStore.alert(e.data.description, 'error')
+
+      let results: (Endpoint | { status: string, data?: { description: string } })[] =
+        await Promise.all(endpoints.map(endpoint => EndpointSource.add(endpoint, true)).map(p => p.catch(e => e)))
+
+      let internalServerErrors = results.filter(r => r.status && r.status === 500)
+      if (internalServerErrors.length > 0) {
+        notificationStore.alert(`There was a problem duplicating ${internalServerErrors.length} endpoint${internalServerErrors.length > 1 ? 's' : ''}`, 'error')
+      }
+      let forbiddenErrors = results.filter(r => r.status && r.status === 403)
+      if (forbiddenErrors.length > 0 && forbiddenErrors[0].data && forbiddenErrors[0].data.description) {
+        notificationStore.alert(String(forbiddenErrors[0].data.description), 'error')
       }
       }
-    })
+    } catch (ex) {
+      if (ex.data && ex.data.description) {
+        notificationStore.alert(ex.data.description, 'error')
+      }
+    }
   }
   }
 
 
   @action setConnectionInfo(connectionInfo: $PropertyType<Endpoint, 'connection_info'>) {
   @action setConnectionInfo(connectionInfo: $PropertyType<Endpoint, 'connection_info'>) {
@@ -128,16 +144,26 @@ class EndpointStore {
     this.connectionInfoLoading = false
     this.connectionInfoLoading = false
   }
   }
 
 
-  @action validate(endpoint: Endpoint) {
+  @action async validate(endpoint: Endpoint) {
     this.validating = true
     this.validating = true
 
 
-    return EndpointSource.validate(endpoint).then(validation => {
-      this.validation = validation
-      this.validating = false
-    }).catch(() => {
-      this.validating = false
-      this.validation = { valid: false, message: '' }
-    })
+    try {
+      let validation = await EndpointSource.validate(endpoint)
+      this.validateSuccess(validation)
+    } catch (ex) {
+      this.validateFailed()
+      throw ex
+    }
+  }
+
+  @action validateSuccess(validation: Validation) {
+    this.validation = validation
+    this.validating = false
+  }
+
+  @action validateFailed() {
+    this.validating = false
+    this.validation = { valid: false, message: '' }
   }
   }
 
 
   @action clearValidation() {
   @action clearValidation() {
@@ -145,53 +171,68 @@ class EndpointStore {
     this.validation = null
     this.validation = null
   }
   }
 
 
-  @action update(endpoint: Endpoint) {
+  @action async update(endpoint: Endpoint) {
     this.endpoints = updateEndpoint(endpoint, this.endpoints)
     this.endpoints = updateEndpoint(endpoint, this.endpoints)
     this.connectionInfo = { ...endpoint.connection_info }
     this.connectionInfo = { ...endpoint.connection_info }
     this.updating = true
     this.updating = true
 
 
-    return EndpointSource.update(endpoint).then(updatedEndpoint => {
-      this.endpoints = updateEndpoint(updatedEndpoint, this.endpoints)
-      this.connectionInfo = { ...updatedEndpoint.connection_info }
-      this.updating = false
-    }).catch(e => {
-      this.updating = false
+    try {
+      let updatedEndpoint = await EndpointSource.update(endpoint)
+      this.updateSuccess(updatedEndpoint)
+    } catch (e) {
+      runInAction(() => { this.updating = false })
       throw e
       throw e
-    })
+    }
+  }
+
+  @action updateSuccess(updatedEndpoint: Endpoint) {
+    this.endpoints = updateEndpoint(updatedEndpoint, this.endpoints)
+    this.connectionInfo = { ...updatedEndpoint.connection_info }
+    this.updating = false
   }
   }
 
 
   @action clearConnectionInfo() {
   @action clearConnectionInfo() {
     this.connectionInfo = null
     this.connectionInfo = null
   }
   }
 
 
-  @action add(endpoint: Endpoint) {
+  @action async add(endpoint: Endpoint) {
     this.adding = true
     this.adding = true
 
 
-    return EndpointSource.add(endpoint).then(addedEndpoint => {
-      this.endpoints = [
-        addedEndpoint,
-        ...this.endpoints,
-      ]
+    try {
+      let addedEndpoint = await EndpointSource.add(endpoint)
+      this.addSuccess(addedEndpoint)
+    } catch (ex) {
+      runInAction(() => { this.adding = false })
+      throw ex
+    }
+  }
 
 
-      this.connectionInfo = addedEndpoint.connection_info
-      this.adding = false
-    }).catch(e => {
-      this.adding = false
-      throw e
-    })
+  @action addSuccess(addedEndpoint: Endpoint) {
+    this.endpoints = [
+      addedEndpoint,
+      ...this.endpoints,
+    ]
+    this.connectionInfo = addedEndpoint.connection_info
+    this.adding = false
   }
   }
 
 
-  @action loadStorage(endpointId: string, data: any): Promise<void> {
+  @action async loadStorage(endpointId: string, data: any): Promise<void> {
     this.storageBackends = []
     this.storageBackends = []
     this.storageLoading = true
     this.storageLoading = true
-    return EndpointSource.loadStorage(endpointId, data).then(storage => {
-      this.storageBackends = storage.storage_backends
-      this.storageConfigDefault = storage.config_default || ''
-      this.storageLoading = false
-    }).catch(ex => {
-      this.storageLoading = false
+
+    try {
+      let storage = await EndpointSource.loadStorage(endpointId, data)
+      this.loadStorageSuccess(storage)
+    } catch (ex) {
+      runInAction(() => { this.storageLoading = false })
       throw ex
       throw ex
-    })
+    }
+  }
+
+  @action loadStorageSuccess(storage: Storage) {
+    this.storageBackends = storage.storage_backends
+    this.storageConfigDefault = storage.config_default || ''
+    this.storageLoading = false
   }
   }
 }
 }
 
 

+ 92 - 67
src/stores/InstanceStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action, computed } from 'mobx'
+import { observable, runInAction, computed, action } from 'mobx'
 
 
 import type { Instance } from '../types/Instance'
 import type { Instance } from '../types/Instance'
 import type { Endpoint } from '../types/Endpoint'
 import type { Endpoint } from '../types/Endpoint'
@@ -117,7 +117,7 @@ class InstanceStore {
   lastEndpointId: string
   lastEndpointId: string
   reqId: number
   reqId: number
 
 
-  @action loadInstancesInChunks(endpoint: Endpoint, vmsPerPage?: number = 6, reload?: boolean) {
+  @action async loadInstancesInChunks(endpoint: Endpoint, vmsPerPage?: number = 6, reload?: boolean) {
     ApiCaller.cancelRequests(`${endpoint.id}-chunk`)
     ApiCaller.cancelRequests(`${endpoint.id}-chunk`)
 
 
     this.backgroundInstances = []
     this.backgroundInstances = []
@@ -131,31 +131,35 @@ class InstanceStore {
     let chunkSize = configLoader.config.instancesListBackgroundLoading
     let chunkSize = configLoader.config.instancesListBackgroundLoading
     let chunkCount = Math.max(chunkSize[endpoint.type] || chunkSize.default, vmsPerPage)
     let chunkCount = Math.max(chunkSize[endpoint.type] || chunkSize.default, vmsPerPage)
 
 
-    let loadNextChunk = (lastEndpointId?: string) => {
+    let loadNextChunk = async (lastEndpointId?: string) => {
       let currentEndpointId = endpoint.id
       let currentEndpointId = endpoint.id
-      InstanceSource.loadInstancesChunk(currentEndpointId, chunkCount, lastEndpointId, `${endpoint.id}-chunk`)
-        .then(instances => {
-          if (currentEndpointId !== this.lastEndpointId) {
-            return
-          }
+      let instances = await InstanceSource.loadInstancesChunk(currentEndpointId, chunkCount, lastEndpointId, `${endpoint.id}-chunk`)
+      if (currentEndpointId !== this.lastEndpointId) {
+        return
+      }
+      let shouldContinue = this.loadInstancesInChunksSuccess(instances, chunkCount, reload)
+      if (shouldContinue) {
+        loadNextChunk(instances[instances.length - 1].id)
+      }
+    }
+    loadNextChunk()
+  }
 
 
-          this.backgroundInstances = [...this.backgroundInstances, ...instances]
-          if (reload) {
-            this.reloading = false
-          }
-          this.instancesLoading = false
+  @action loadInstancesInChunksSuccess(instances: Instance[], chunkCount: number, reload?: boolean): boolean {
+    this.backgroundInstances = [...this.backgroundInstances, ...instances]
+    if (reload) {
+      this.reloading = false
+    }
+    this.instancesLoading = false
 
 
-          if (instances.length < chunkCount) {
-            this.backgroundChunksLoading = false
-            return
-          }
-          loadNextChunk(instances[instances.length - 1].id)
-        })
+    if (instances.length < chunkCount) {
+      this.backgroundChunksLoading = false
+      return false
     }
     }
-    loadNextChunk()
+    return true
   }
   }
 
 
-  @action loadInstances(endpointId: string): Promise<void> {
+  @action async loadInstances(endpointId: string): Promise<void> {
     this.instancesLoading = true
     this.instancesLoading = true
     this.lastEndpointId = endpointId
     this.lastEndpointId = endpointId
 
 
@@ -163,25 +167,31 @@ class InstanceStore {
     if (endpointInstances) {
     if (endpointInstances) {
       this.backgroundInstances = endpointInstances
       this.backgroundInstances = endpointInstances
       this.instancesLoading = false
       this.instancesLoading = false
-      return Promise.resolve()
+      return
     }
     }
 
 
-    return InstanceSource.loadInstances(endpointId).then(instances => {
+    try {
+      let instances = await InstanceSource.loadInstances(endpointId)
       if (endpointId !== this.lastEndpointId) {
       if (endpointId !== this.lastEndpointId) {
         return
         return
       }
       }
-      this.backgroundInstances = instances
-      this.instancesLoading = false
+      this.loadInstancesSuccess(instances)
       InstanceLocalStorage.saveInstancesToLocalStorage(endpointId, instances)
       InstanceLocalStorage.saveInstancesToLocalStorage(endpointId, instances)
-    }).catch(() => {
+    } catch (ex) {
       if (endpointId !== this.lastEndpointId) {
       if (endpointId !== this.lastEndpointId) {
         return
         return
       }
       }
-      this.instancesLoading = false
-    })
+      runInAction(() => { this.instancesLoading = false })
+      throw ex
+    }
   }
   }
 
 
-  @action searchInstances(endpoint: Endpoint, searchText: string) {
+  @action loadInstancesSuccess(instances: Instance[]) {
+    this.backgroundInstances = instances
+    this.instancesLoading = false
+  }
+
+  @action async searchInstances(endpoint: Endpoint, searchText: string) {
     ApiCaller.cancelRequests(`${endpoint.id}-chunk-search`)
     ApiCaller.cancelRequests(`${endpoint.id}-chunk-search`)
 
 
     this.searchText = searchText
     this.searchText = searchText
@@ -203,34 +213,43 @@ class InstanceStore {
 
 
     this.searching = true
     this.searching = true
     this.searchChunksLoading = true
     this.searchChunksLoading = true
+
     let chunkSize = configLoader.config.instancesListBackgroundLoading
     let chunkSize = configLoader.config.instancesListBackgroundLoading
     let chunkCount = Math.max(chunkSize[endpoint.type] || chunkSize.default, this.instancesPerPage)
     let chunkCount = Math.max(chunkSize[endpoint.type] || chunkSize.default, this.instancesPerPage)
 
 
-    let loadNextChunk = (lastEndpointId?: string) => {
-      InstanceSource.loadInstancesChunk(
+    let loadNextChunk = async (lastEndpointId?: string) => {
+      let instances = await InstanceSource.loadInstancesChunk(
         endpoint.id,
         endpoint.id,
         chunkCount,
         chunkCount,
         lastEndpointId,
         lastEndpointId,
         `${endpoint.id}-chunk-search`,
         `${endpoint.id}-chunk-search`,
         searchText
         searchText
-      ).then(instances => {
-        if (this.searching) {
+      )
+      if (this.searching) {
+        runInAction(() => {
           this.currentPage = 1
           this.currentPage = 1
           this.searchedInstances = []
           this.searchedInstances = []
-        }
-
-        this.searchedInstances = [...this.searchedInstances, ...instances]
-        this.searching = false
-        this.searchNotFound = Boolean(this.searchedInstances.length === 0)
-        if (instances.length < chunkCount) {
-          this.searchChunksLoading = false
-        }
-        return loadNextChunk(instances[instances.length - 1].id)
-      })
+        })
+      }
+      let shouldContinue = this.searchInstancesSuccess(instances, chunkCount)
+      if (shouldContinue) {
+        loadNextChunk(instances[instances.length - 1].id)
+      }
     }
     }
     loadNextChunk()
     loadNextChunk()
   }
   }
 
 
+  @action searchInstancesSuccess(instances: Instance[], chunkCount: number): boolean {
+    this.searchedInstances = [...this.searchedInstances, ...instances]
+    this.searching = false
+    this.searchNotFound = Boolean(this.searchedInstances.length === 0)
+    if (instances.length < chunkCount) {
+      this.searchChunksLoading = false
+      return false
+    }
+    return true
+  }
+
   @action reloadInstances(endpoint: Endpoint, chunkSize?: number) {
   @action reloadInstances(endpoint: Endpoint, chunkSize?: number) {
     this.searchNotFound = false
     this.searchNotFound = false
     this.searchText = ''
     this.searchText = ''
@@ -255,7 +274,7 @@ class InstanceStore {
     this.instancesPerPage = instancesPerPage
     this.instancesPerPage = instancesPerPage
   }
   }
 
 
-  @action loadInstancesDetails(endpointId: string, instancesInfo: Instance[], useLocalStorage?: boolean, quietError?: boolean): Promise<void> {
+  @action async loadInstancesDetails(endpointId: string, instancesInfo: Instance[], useLocalStorage?: boolean, quietError?: boolean): Promise<void> {
     // Use reqId to be able to uniquely identify the request so all but the latest request can be igonred and canceled
     // Use reqId to be able to uniquely identify the request so all but the latest request can be igonred and canceled
     this.reqId = !this.reqId ? 1 : this.reqId + 1
     this.reqId = !this.reqId ? 1 : this.reqId + 1
     InstanceSource.cancelInstancesDetailsRequests(this.reqId - 1)
     InstanceSource.cancelInstancesDetailsRequests(this.reqId - 1)
@@ -263,7 +282,7 @@ class InstanceStore {
     instancesInfo.sort((a, b) => a.instance_name.localeCompare(b.instance_name))
     instancesInfo.sort((a, b) => a.instance_name.localeCompare(b.instance_name))
     let hash = i => `${i.instance_name}-${i.id || endpointId}`
     let hash = i => `${i.instance_name}-${i.id || endpointId}`
     if (useLocalStorage && this.instancesDetails.map(hash).join('_') === instancesInfo.map(hash).join('_')) {
     if (useLocalStorage && this.instancesDetails.map(hash).join('_') === instancesInfo.map(hash).join('_')) {
-      return Promise.resolve()
+      return
     }
     }
 
 
     let count = instancesInfo.length
     let count = instancesInfo.length
@@ -280,48 +299,54 @@ class InstanceStore {
         this.instancesDetails = storageInstances
         this.instancesDetails = storageInstances
         this.loadingInstancesDetails = false
         this.loadingInstancesDetails = false
         this.instancesDetailsRemaining = 0
         this.instancesDetailsRemaining = 0
-        return Promise.resolve()
+        return
       }
       }
     }
     }
-
-    return new Promise((resolve) => {
-      instancesInfo.forEach(instanceInfo => {
-        InstanceSource.loadInstanceDetails(endpointId, instanceInfo.instance_name, this.reqId, quietError).then((resp: { instance: Instance, reqId: number }) => {
+    await new Promise(resolve => {
+      Promise.all(instancesInfo.map(async instanceInfo => {
+        try {
+          let resp: { instance: Instance, reqId: number } =
+            await InstanceSource.loadInstanceDetails(endpointId, instanceInfo.instance_name, this.reqId, quietError)
           if (resp.reqId !== this.reqId) {
           if (resp.reqId !== this.reqId) {
             return
             return
           }
           }
 
 
-          this.instancesDetailsRemaining -= 1
-          this.loadingInstancesDetails = this.instancesDetailsRemaining > 0
+          runInAction(() => {
+            this.instancesDetailsRemaining -= 1
+            this.loadingInstancesDetails = this.instancesDetailsRemaining > 0
 
 
-          if (this.instancesDetails.find(i => i.id === resp.instance.id)) {
-            this.instancesDetails = this.instancesDetails.filter(i => i.id !== resp.instance.id)
-          }
+            if (this.instancesDetails.find(i => i.id === resp.instance.id)) {
+              this.instancesDetails = this.instancesDetails.filter(i => i.id !== resp.instance.id)
+            }
+          })
 
 
           InstanceLocalStorage.saveDetailsToLocalStorage(endpointId, resp.instance)
           InstanceLocalStorage.saveDetailsToLocalStorage(endpointId, resp.instance)
 
 
-          this.instancesDetails = [
-            ...this.instancesDetails,
-            resp.instance,
-          ]
-          this.instancesDetails.sort((a, b) => a.instance_name.localeCompare(b.instance_name))
-
+          runInAction(() => {
+            this.instancesDetails = [
+              ...this.instancesDetails,
+              resp.instance,
+            ]
+            this.instancesDetails.sort((a, b) => a.instance_name.localeCompare(b.instance_name))
+          })
           if (this.instancesDetailsRemaining === 0) {
           if (this.instancesDetailsRemaining === 0) {
             resolve()
             resolve()
           }
           }
-        }).catch((resp?: { reqId: number }) => {
-          this.instancesDetailsRemaining -= 1
-          this.loadingInstancesDetails = this.instancesDetailsRemaining > 0
+        } catch (err) {
+          runInAction(() => {
+            this.instancesDetailsRemaining -= 1
+            this.loadingInstancesDetails = this.instancesDetailsRemaining > 0
+          })
 
 
-          if (!resp || resp.reqId !== this.reqId) {
+          if (!err || err.reqId !== this.reqId) {
             return
             return
           }
           }
 
 
           if (count === 0) {
           if (count === 0) {
             resolve()
             resolve()
           }
           }
-        })
-      })
+        }
+      }))
     })
     })
   }
   }
 
 

+ 48 - 37
src/stores/MigrationStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 
 
 import type { MainItem, UpdateData } from '../types/MainItem'
 import type { MainItem, UpdateData } from '../types/MainItem'
 import type { Field } from '../types/Field'
 import type { Field } from '../types/Field'
@@ -30,29 +30,38 @@ class MigrationStore {
 
 
   migrationsLoaded: boolean = false
   migrationsLoaded: boolean = false
 
 
-  @action getMigrations(options?: { showLoading?: boolean, skipLog?: boolean }) {
+  @action async getMigrations(options?: { showLoading?: boolean, skipLog?: boolean }) {
     if ((options && options.showLoading) || !this.migrationsLoaded) {
     if ((options && options.showLoading) || !this.migrationsLoaded) {
       this.loading = true
       this.loading = true
     }
     }
 
 
-    return MigrationSource.getMigrations(options && options.skipLog).then(migrations => {
-      this.migrations = migrations.map(migration => {
-        let oldMigration = this.migrations.find(r => r.id === migration.id)
-        if (oldMigration) {
-          migration.executions = oldMigration.executions
-        }
-
-        return migration
+    try {
+      let migrations = await MigrationSource.getMigrations(options && options.skipLog)
+      runInAction(() => {
+        this.migrations = migrations.map(migration => {
+          let oldMigration = this.migrations.find(r => r.id === migration.id)
+          if (oldMigration) {
+            migration.executions = oldMigration.executions
+          }
+
+          return migration
+        })
+        this.loading = false
+        this.migrationsLoaded = true
       })
       })
-      this.loading = false
-      this.migrationsLoaded = true
-    }).catch(() => {
-      this.loading = false
-    })
+    } catch (ex) {
+      runInAction(() => { this.loading = false })
+      throw ex
+    }
   }
   }
 
 
-  @action recreate(migration: MainItem, sourceEndpoint: Endpoint, destEndpoint: Endpoint, updateData: UpdateData): Promise<MainItem> {
-    return MigrationSource.recreate({
+  @action async recreate(
+    migration: MainItem,
+    sourceEndpoint: Endpoint,
+    destEndpoint: Endpoint,
+    updateData: UpdateData
+  ): Promise<MainItem> {
+    let migrationResult = await MigrationSource.recreate({
       sourceEndpoint,
       sourceEndpoint,
       destEndpoint,
       destEndpoint,
       instanceNames: migration.instances,
       instanceNames: migration.instances,
@@ -65,42 +74,44 @@ class MigrationStore {
       networkMappings: migration.network_map,
       networkMappings: migration.network_map,
       updatedNetworkMappings: updateData.network,
       updatedNetworkMappings: updateData.network,
     })
     })
+    return migrationResult
   }
   }
 
 
-  @action getMigration(migrationId: string, options?: { showLoading?: boolean, skipLog?: boolean }) {
+  @action async getMigration(migrationId: string, options?: { showLoading?: boolean, skipLog?: boolean }) {
     this.detailsLoading = Boolean(options && options.showLoading)
     this.detailsLoading = Boolean(options && options.showLoading)
 
 
-    return MigrationSource.getMigration(migrationId, options && options.skipLog).then(migration => {
-      this.detailsLoading = false
-      this.migrationDetails = migration
-    }).catch(() => {
-      this.detailsLoading = false
-    })
+    try {
+      let migration = await MigrationSource.getMigration(migrationId, options && options.skipLog)
+      runInAction(() => { this.migrationDetails = migration })
+    } finally {
+      runInAction(() => { this.detailsLoading = false })
+    }
   }
   }
 
 
-  @action cancel(migrationId: string) {
+  @action async cancel(migrationId: string) {
     this.canceling = true
     this.canceling = true
-    return MigrationSource.cancel(migrationId).then(() => {
-      this.canceling = false
-    }).catch(() => {
-      this.canceling = { failed: true }
-    })
+    try {
+      await MigrationSource.cancel(migrationId)
+      runInAction(() => { this.canceling = false })
+    } catch (ex) {
+      runInAction(() => { this.canceling = { failed: true } })
+    }
   }
   }
 
 
-  @action delete(migrationId: string) {
-    return MigrationSource.delete(migrationId).then(() => {
-      this.migrations = this.migrations.filter(r => r.id !== migrationId)
-    })
+  @action async delete(migrationId: string) {
+    await MigrationSource.delete(migrationId)
+    runInAction(() => { this.migrations = this.migrations.filter(r => r.id !== migrationId) })
   }
   }
 
 
-  @action migrateReplica(replicaId: string, options: Field[]): Promise<MainItem> {
-    return MigrationSource.migrateReplica(replicaId, options).then(migration => {
+  @action async migrateReplica(replicaId: string, options: Field[]) {
+    let migration = await MigrationSource.migrateReplica(replicaId, options)
+    runInAction(() => {
       this.migrations = [
       this.migrations = [
         migration,
         migration,
         ...this.migrations,
         ...this.migrations,
       ]
       ]
-      return migration
     })
     })
+    return migration
   }
   }
 
 
   @action clearDetails() {
   @action clearDetails() {

+ 14 - 12
src/stores/NetworkStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 import type { Network } from '../types/Network'
 import type { Network } from '../types/Network'
 import NetworkSource from '../sources/NetworkSource'
 import NetworkSource from '../sources/NetworkSource'
 
 
@@ -45,13 +45,13 @@ class NetworkStore {
 
 
   cachedId: string = ''
   cachedId: string = ''
 
 
-  @action loadNetworks(endpointId: string, environment: any, options?: {
+  @action async loadNetworks(endpointId: string, environment: any, options?: {
     useLocalStorage?: boolean,
     useLocalStorage?: boolean,
     quietError?: boolean,
     quietError?: boolean,
-  }): Promise<void> {
+  }) {
     let id = `${endpointId}-${btoa(JSON.stringify(environment))}`
     let id = `${endpointId}-${btoa(JSON.stringify(environment))}`
     if (this.cachedId === id && options && options.useLocalStorage) {
     if (this.cachedId === id && options && options.useLocalStorage) {
-      return Promise.resolve()
+      return
     }
     }
 
 
     this.loading = true
     this.loading = true
@@ -62,20 +62,22 @@ class NetworkStore {
         this.loading = false
         this.loading = false
         this.networks = networkStorage
         this.networks = networkStorage
         this.cachedId = id
         this.cachedId = id
-        return Promise.resolve()
+        return
       }
       }
     }
     }
 
 
     this.networks = []
     this.networks = []
-    return NetworkSource.loadNetworks(endpointId, environment, options).then((networks: Network[]) => {
-      this.loading = false
-      this.networks = networks
-      this.cachedId = id
-
+    try {
+      let networks = await NetworkSource.loadNetworks(endpointId, environment, options)
+      runInAction(() => {
+        this.loading = false
+        this.networks = networks
+        this.cachedId = id
+      })
       NetworkLocalStorage.saveNetworksToLocalStorage(id, networks)
       NetworkLocalStorage.saveNetworksToLocalStorage(id, networks)
-    }).catch(() => {
+    } catch (e) {
       this.loading = false
       this.loading = false
-    })
+    }
   }
   }
 }
 }
 
 

+ 4 - 7
src/stores/NotificationStore.js

@@ -25,7 +25,7 @@ class NotificationStore {
 
 
   visibleErrors: string[] = []
   visibleErrors: string[] = []
 
 
-  @action alert(message: string, level?: $PropertyType<AlertInfo, 'level'>, options?: $PropertyType<AlertInfo, 'options'>): Promise<void> {
+  @action alert(message: string, level?: $PropertyType<AlertInfo, 'level'>, options?: $PropertyType<AlertInfo, 'options'>) {
     if (!this.visibleErrors.find(e => e === message)) {
     if (!this.visibleErrors.find(e => e === message)) {
       this.alerts.push({ message, level, options })
       this.alerts.push({ message, level, options })
 
 
@@ -34,14 +34,11 @@ class NotificationStore {
         setTimeout(() => { this.visibleErrors = this.visibleErrors.filter(e => e !== message) }, 10000)
         setTimeout(() => { this.visibleErrors = this.visibleErrors.filter(e => e !== message) }, 10000)
       }
       }
     }
     }
-
-    return Promise.resolve()
   }
   }
 
 
-  @action loadData(): Promise<void> {
-    return NotificationSource.loadData().then(data => {
-      this.notificationItems = data
-    })
+  @action async loadData() {
+    let data = await NotificationSource.loadData()
+    this.notificationItems = data
   }
   }
 
 
   @action saveSeen() {
   @action saveSeen() {

+ 74 - 60
src/stores/ProjectStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 import type { Project, RoleAssignment, Role } from '../types/Project'
 import type { Project, RoleAssignment, Role } from '../types/Project'
 import type { User } from '../types/User'
 import type { User } from '../types/User'
 
 
@@ -31,46 +31,55 @@ class ProjectStore {
   @observable usersLoading: boolean = false
   @observable usersLoading: boolean = false
   @observable updating: boolean = false
   @observable updating: boolean = false
 
 
-  @action getProjects(options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
+  @action async getProjects(options?: { showLoading?: boolean, skipLog?: boolean }) {
     if (options && options.showLoading) this.loading = true
     if (options && options.showLoading) this.loading = true
-    return ProjectSource.getProjects(options && options.skipLog).then((projects: Project[]) => {
-      this.loading = false
-      this.projects = projects
-    }).catch(() => {
-      this.loading = false
-    })
+    try {
+      let projects = await ProjectSource.getProjects(options && options.skipLog)
+      runInAction(() => {
+        this.loading = false
+        this.projects = projects
+      })
+    } catch (e) {
+      runInAction(() => { this.loading = false })
+    }
   }
   }
 
 
-  @action getRoleAssignments(options?: { skipLog?: boolean }): Promise<void> {
-    return ProjectSource.getRoleAssignments(options && options.skipLog).then((assignments: RoleAssignment[]) => {
+  @action async getRoleAssignments(options?: { skipLog?: boolean }) {
+    let assignments = await ProjectSource.getRoleAssignments(options && options.skipLog)
+    runInAction(() => {
       this.roleAssignments = assignments
       this.roleAssignments = assignments
     })
     })
   }
   }
 
 
-  @action getRoles(): Promise<void> {
-    return ProjectSource.getRoles().then((roles: Role[]) => {
-      this.roles = roles
-    })
+  @action async getRoles() {
+    let roles = await ProjectSource.getRoles()
+    runInAction(() => { this.roles = roles })
   }
   }
 
 
-  @action getProjectDetails(projectId: string): Promise<void> {
+  @action async getProjectDetails(projectId: string) {
     this.loading = true
     this.loading = true
-    return ProjectSource.getProjectDetails(projectId).then((project: Project) => {
-      this.projectDetails = project
-      this.loading = false
-    }).catch(() => {
-      this.loading = false
-    })
+    try {
+      let project = await ProjectSource.getProjectDetails(projectId)
+      runInAction(() => {
+        this.projectDetails = project
+        this.loading = false
+      })
+    } catch (e) {
+      runInAction(() => { this.loading = false })
+    }
   }
   }
 
 
-  @action getUsers(projectId: string, showLoading?: boolean): Promise<void> {
+  @action async getUsers(projectId: string, showLoading?: boolean) {
     if (showLoading) this.usersLoading = true
     if (showLoading) this.usersLoading = true
-    return ProjectSource.getUsers(projectId).then((users: User[]) => {
-      this.usersLoading = false
-      this.users = users
-    }).catch(() => {
-      this.usersLoading = false
-    })
+    try {
+      let users = await ProjectSource.getUsers(projectId)
+      runInAction(() => {
+        this.usersLoading = false
+        this.users = users
+      })
+    } catch (e) {
+      runInAction(() => { this.usersLoading = false })
+    }
   }
   }
 
 
   @action clearProjectDetails() {
   @action clearProjectDetails() {
@@ -78,51 +87,56 @@ class ProjectStore {
     this.users = []
     this.users = []
   }
   }
 
 
-  @action removeUser(projectId: string, userId: string, roleIds: string[]): Promise<void> {
-    return ProjectSource.removeUser(projectId, userId, roleIds).then(() => {
-      this.users = this.users.filter(u => u.id !== userId)
-    })
+  @action async removeUser(projectId: string, userId: string, roleIds: string[]) {
+    await ProjectSource.removeUser(projectId, userId, roleIds)
+    runInAction(() => { this.users = this.users.filter(u => u.id !== userId) })
   }
   }
 
 
-  @action assignUserRole(projectId: string, userId: string, roleId: string): Promise<void> {
-    return ProjectSource.assignUser(projectId, userId, roleId)
+  @action async assignUserRole(projectId: string, userId: string, roleId: string) {
+    await ProjectSource.assignUser(projectId, userId, roleId)
   }
   }
 
 
-  @action removeUserRole(projectId: string, userId: string, roleId: string): Promise<void> {
-    return ProjectSource.removeUser(projectId, userId, [roleId])
+  @action async removeUserRole(projectId: string, userId: string, roleId: string) {
+    await ProjectSource.removeUser(projectId, userId, [roleId])
   }
   }
 
 
-  @action update(projectId: string, project: Project): Promise<void> {
+  @action async update(projectId: string, project: Project) {
     this.updating = true
     this.updating = true
-    return ProjectSource.update(projectId, project).then((project: Project) => {
-      this.projectDetails = project
-      this.updating = false
-    }).catch(() => {
-      this.updating = false
-    })
+    try {
+      let updatedProject = await ProjectSource.update(projectId, project)
+      runInAction(() => {
+        this.projectDetails = updatedProject
+        this.updating = false
+      })
+    } catch (e) {
+      runInAction(() => { this.updating = false })
+    }
   }
   }
 
 
-  @action delete(projectId: string): Promise<void> {
-    return ProjectSource.delete(projectId)
+  @action async delete(projectId: string) {
+    await ProjectSource.delete(projectId)
   }
   }
 
 
-  @action add(project: Project): Promise<void> {
+  @action async add(project: Project) {
     this.updating = true
     this.updating = true
     let userId = userStore.loggedUser ? userStore.loggedUser.id : 'undefined'
     let userId = userStore.loggedUser ? userStore.loggedUser.id : 'undefined'
-    return ProjectSource.add(project, userId).then((addedProject: Project) => {
-      if (!this.projects.find(p => p.id === addedProject.id)) {
-        let projects = this.projects
-        projects = [
-          ...projects,
-          addedProject,
-        ]
-        projects.sort((a, b) => a.name.localeCompare(b.name))
-        this.projects = [...projects]
-      }
-      this.updating = false
-    }).catch(() => {
-      this.updating = false
-    })
+    try {
+      let addedProject = await ProjectSource.add(project, userId)
+      runInAction(() => {
+        if (!this.projects.find(p => p.id === addedProject.id)) {
+          let projects = this.projects
+          projects = [
+            ...projects,
+            addedProject,
+          ]
+          projects.sort((a, b) => a.name.localeCompare(b.name))
+          this.projects = [...projects]
+        }
+        this.updating = false
+      })
+    } catch (e) {
+      runInAction(() => { this.updating = false })
+    }
   }
   }
 }
 }
 
 

+ 122 - 105
src/stores/ProviderStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action, computed } from 'mobx'
+import { observable, action, computed, runInAction } from 'mobx'
 
 
 import ProviderSource from '../sources/ProviderSource'
 import ProviderSource from '../sources/ProviderSource'
 import configLoader from '../utils/Config'
 import configLoader from '../utils/Config'
@@ -25,16 +25,16 @@ import type { Field } from '../types/Field'
 import type { Providers } from '../types/Providers'
 import type { Providers } from '../types/Providers'
 
 
 export const getFieldChangeOptions = (config: {
 export const getFieldChangeOptions = (config: {
-  provider: ?string,
+  providerName: ?string,
   schema: Field[],
   schema: Field[],
   data: any,
   data: any,
   field: ?Field,
   field: ?Field,
   type: 'source' | 'destination',
   type: 'source' | 'destination',
 }) => {
 }) => {
-  let { provider, schema, data, field, type } = config
-  let providerWithEnvOptions = configLoader.config.providersWithEnvOptions.find(p => p.name === provider && p.type === type)
+  let { providerName, schema, data, field, type } = config
+  let providerWithEnvOptions = configLoader.config.providersWithEnvOptions.find(p => p.name === providerName && p.type === type)
 
 
-  if (!provider || !providerWithEnvOptions) {
+  if (!providerName || !providerWithEnvOptions) {
     return null
     return null
   }
   }
   let envRequiredFields = providerWithEnvOptions.envRequiredFields
   let envRequiredFields = providerWithEnvOptions.envRequiredFields
@@ -88,8 +88,8 @@ class ProviderStore {
   @observable sourceSchema: Field[] = []
   @observable sourceSchema: Field[] = []
   @observable sourceSchemaLoading: boolean = false
   @observable sourceSchemaLoading: boolean = false
 
 
-  lastDestinationSchemaType: string = ''
-  lastSourceSchemaType: string = ''
+  lastDestinationSchemaType: 'replica' | 'migration' = 'replica'
+  lastSourceSchemaType: 'replica' | 'migration' = 'replica'
 
 
   @computed
   @computed
   get providerNames(): string[] {
   get providerNames(): string[] {
@@ -110,145 +110,162 @@ class ProviderStore {
     return array
     return array
   }
   }
 
 
-  @action getConnectionInfoSchema(providerName: string): Promise<void> {
+  @action async getConnectionInfoSchema(providerName: string): Promise<void> {
     this.connectionSchemaLoading = true
     this.connectionSchemaLoading = true
 
 
-    return ProviderSource.getConnectionInfoSchema(providerName).then((fields: Field[]) => {
-      this.connectionSchemaLoading = false
-      this.connectionInfoSchema = fields
-    }).catch(() => {
-      this.connectionSchemaLoading = false
-    })
+    try {
+      let fields: Field[] = await ProviderSource.getConnectionInfoSchema(providerName)
+      runInAction(() => { this.connectionInfoSchema = fields })
+    } finally {
+      runInAction(() => { this.connectionSchemaLoading = false })
+    }
   }
   }
 
 
   @action clearConnectionInfoSchema() {
   @action clearConnectionInfoSchema() {
     this.connectionInfoSchema = []
     this.connectionInfoSchema = []
   }
   }
 
 
-  @action loadProviders(): Promise<void> {
+  @action async loadProviders(): Promise<void> {
     if (this.providers) {
     if (this.providers) {
-      return Promise.resolve()
+      return
     }
     }
-
     this.providersLoading = true
     this.providersLoading = true
-
-    return ProviderSource.loadProviders().then((providers: Providers) => {
-      this.providers = providers
-      this.providersLoading = false
-    }).catch(() => {
-      this.providersLoading = false
-    })
+    try {
+      let providers: Providers = await ProviderSource.loadProviders()
+      runInAction(() => { this.providers = providers })
+    } finally {
+      runInAction(() => { this.providersLoading = false })
+    }
   }
   }
 
 
   destinationSchemaCache: { [string]: Field[] } = {}
   destinationSchemaCache: { [string]: Field[] } = {}
-  @action loadDestinationSchema(providerName: string, schemaType: string, cache?: boolean): Promise<void> {
-    this.lastDestinationSchemaType = schemaType
+  sourceSchemaCache: { [string]: Field[] } = {}
+
+  @action async loadOptionsSchema(options: {
+    providerName: string,
+    schemaType: 'migration' | 'replica',
+    optionsType: 'source' | 'destination',
+    useCache?: boolean,
+  }): Promise<void> {
+    let { schemaType, providerName, optionsType, useCache } = options
+    let cacheData: any
 
 
     let cacheKey = `${providerName}-${schemaType}`
     let cacheKey = `${providerName}-${schemaType}`
-    let cacheData = this.destinationSchemaCache[cacheKey]
-    if (cache && cacheData) {
-      this.destinationSchema = [...cacheData]
-      return Promise.resolve()
+    if (optionsType === 'source') {
+      cacheData = this.sourceSchemaCache[cacheKey]
+      this.lastSourceSchemaType = schemaType
+    } else {
+      cacheData = this.destinationSchemaCache[cacheKey]
+      this.lastDestinationSchemaType = schemaType
+    }
+    if (useCache && cacheData) {
+      if (optionsType === 'source') {
+        this.sourceSchema = [...cacheData]
+      } else {
+        this.destinationSchema = [...cacheData]
+      }
+      return
     }
     }
 
 
-    this.destinationSchemaLoading = true
+    if (optionsType === 'source') {
+      this.sourceSchemaLoading = true
+    } else {
+      this.destinationSchemaLoading = true
+    }
 
 
-    return ProviderSource.loadDestinationSchema(providerName, schemaType).then((fields: Field[]) => {
-      this.destinationSchemaLoading = false
-      this.destinationSchema = fields
-      this.destinationSchemaCache[cacheKey] = fields
-    }).catch(err => {
-      this.destinationSchemaLoading = false
+    try {
+      let fields: Field[] = await ProviderSource.loadOptionsSchema(providerName, schemaType, optionsType)
+      this.loadOptionsSchemaSuccess(fields, cacheKey, optionsType)
+    } catch (err) {
       throw err
       throw err
-    })
-  }
-
-  sourceSchemaCache: { [string]: Field[] } = {}
-  @action loadSourceSchema(providerName: string, schemaType: string, useCache?: boolean): Promise<void> {
-    this.lastSourceSchemaType = schemaType
-
-    let cacheKey = `${providerName}-${schemaType}`
-    let cacheData = this.sourceSchemaCache[cacheKey]
-    if (useCache && cacheData) {
-      this.sourceSchema = [...cacheData]
-      return Promise.resolve()
+    } finally {
+      this.loadOptionsSchemaDone(optionsType)
     }
     }
+  }
 
 
-    this.sourceSchemaLoading = true
-
-    return ProviderSource.loadSourceSchema(providerName, schemaType).then((fields: Field[]) => {
-      this.sourceSchemaLoading = false
+  @action loadOptionsSchemaSuccess(fields: Field[], cacheKey: string, optionsType: 'source' | 'destination') {
+    if (optionsType === 'source') {
       this.sourceSchema = fields
       this.sourceSchema = fields
       this.sourceSchemaCache[cacheKey] = fields
       this.sourceSchemaCache[cacheKey] = fields
-    }).catch(err => {
+    } else {
+      this.destinationSchema = fields
+      this.destinationSchemaCache[cacheKey] = fields
+    }
+  }
+
+  @action loadOptionsSchemaDone(optionsType: 'source' | 'destination') {
+    if (optionsType === 'source') {
       this.sourceSchemaLoading = false
       this.sourceSchemaLoading = false
-      throw err
-    })
+    } else {
+      this.destinationSchemaLoading = false
+    }
   }
   }
 
 
   cache: { key: string, data: OptionValues[] }[] = []
   cache: { key: string, data: OptionValues[] }[] = []
 
 
-  @action getOptionsValues(config: {
+  async getOptionsValues(config: {
     optionsType: 'source' | 'destination',
     optionsType: 'source' | 'destination',
     endpointId: string,
     endpointId: string,
-    provider: string,
+    providerName: string,
     envData?: { [string]: mixed },
     envData?: { [string]: mixed },
     useCache?: boolean,
     useCache?: boolean,
   }): Promise<OptionValues[]> {
   }): Promise<OptionValues[]> {
-    return this.loadProviders().then(() => {
-      let { provider, optionsType, endpointId, envData, useCache } = config
-      let providerType = optionsType === 'source' ? providerTypes.SOURCE_OPTIONS : providerTypes.DESTINATION_OPTIONS
-      if (!this.providers) {
-        return Promise.resolve([])
-      }
-      let providerWithExtraOptions = this.providers[provider].types.find(t => t === providerType)
-      if (!providerWithExtraOptions) {
-        return Promise.resolve([])
+    let { providerName, optionsType, endpointId, envData, useCache } = config
+    let providerType = optionsType === 'source' ? providerTypes.SOURCE_OPTIONS : providerTypes.DESTINATION_OPTIONS
+
+    await this.loadProviders()
+    if (!this.providers) {
+      return []
+    }
+    let providerWithExtraOptions = this.providers[providerName].types.find(t => t === providerType)
+    if (!providerWithExtraOptions) {
+      return []
+    }
+
+    if (useCache) {
+      let key = `${endpointId}-${providerName}-${optionsType}-${JSON.stringify(envData)}`
+      let cacheItem = this.cache.find(c => c.key === key)
+      if (cacheItem) {
+        this.getOptionsValuesSuccess(optionsType, providerName, cacheItem.data)
+        this.getOptionsValuesDone(optionsType)
+        return cacheItem.data
       }
       }
+    }
+
+    this.getOptionsValuesStart(optionsType)
 
 
+    try {
+      let options = await ProviderSource.getOptionsValues(optionsType, endpointId, envData)
+      this.getOptionsValuesSuccess(optionsType, providerName, options)
       if (useCache) {
       if (useCache) {
-        let key = `${endpointId}-${provider}-${optionsType}-${JSON.stringify(envData)}`
-        let cacheItem = this.cache.find(c => c.key === key)
-        if (cacheItem) {
-          this.getOptionsValuesSuccess(optionsType, provider, cacheItem.data)
-          this.getOptionsValuesDone(optionsType)
-          return Promise.resolve(cacheItem.data)
+        let key = `${endpointId}-${providerName}-${optionsType}-${JSON.stringify(envData)}`
+        if (this.cache.length > 20) {
+          this.cache.splice(0)
         }
         }
+        this.cache.push({ key, data: options })
       }
       }
-
-      if (optionsType === 'source') {
-        this.sourceOptionsLoading = true
-        this.sourceOptions = []
-      } else {
-        this.destinationOptionsLoading = true
-        this.destinationOptions = []
+      return options
+    } catch (err) {
+      console.error(err)
+      let schemaType = optionsType === 'source' ? this.lastSourceSchemaType : this.lastDestinationSchemaType
+      if (!envData) {
+        return []
       }
       }
+      let newOptions = await this.loadOptionsSchema({ providerName, schemaType, optionsType })
+      return newOptions
+    } finally {
+      this.getOptionsValuesDone(optionsType)
+    }
+  }
 
 
-      let optionsValues = []
-
-      return ProviderSource.getOptionsValues(optionsType, endpointId, envData).then(options => {
-        this.getOptionsValuesSuccess(optionsType, provider, options)
-        optionsValues = options
-        if (useCache) {
-          let key = `${endpointId}-${provider}-${optionsType}-${JSON.stringify(envData)}`
-          if (this.cache.length > 20) {
-            this.cache.splice(0)
-          }
-          this.cache.push({ key, data: options })
-        }
-      }).catch(err => {
-        console.error(err)
-        if (optionsType === 'source') {
-          return this.loadSourceSchema(provider, this.lastSourceSchemaType)
-            .then(() => envData ? this.getOptionsValues({ endpointId, provider, optionsType }) : null)
-        }
-        return this.loadDestinationSchema(provider, this.lastDestinationSchemaType)
-          .then(() => envData ? this.getOptionsValues({ endpointId, provider, optionsType }) : null)
-      }).then(() => {
-        this.getOptionsValuesDone(optionsType)
-        return optionsValues
-      })
-    })
+  @action getOptionsValuesStart(optionsType: 'source' | 'destination') {
+    if (optionsType === 'source') {
+      this.sourceOptionsLoading = true
+      this.sourceOptions = []
+    } else {
+      this.destinationOptionsLoading = true
+      this.destinationOptions = []
+    }
   }
   }
 
 
   @action getOptionsValuesDone(optionsType: 'source' | 'destination') {
   @action getOptionsValuesDone(optionsType: 'source' | 'destination') {

+ 95 - 76
src/stores/ReplicaStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 
 
 import notificationStore from '../stores/NotificationStore'
 import notificationStore from '../stores/NotificationStore'
 import ReplicaSource from '../sources/ReplicaSource'
 import ReplicaSource from '../sources/ReplicaSource'
@@ -49,113 +49,132 @@ class ReplicaStore {
 
 
   replicasLoaded: boolean = false
   replicasLoaded: boolean = false
 
 
-  @action getReplicas(options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
+  @action async getReplicas(options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
     this.backgroundLoading = true
     this.backgroundLoading = true
 
 
     if ((options && options.showLoading) || !this.replicasLoaded) {
     if ((options && options.showLoading) || !this.replicasLoaded) {
       this.loading = true
       this.loading = true
     }
     }
 
 
-    return ReplicaSource.getReplicas(options && options.skipLog).then(replicas => {
-      this.replicas = replicas
-      this.loading = false
-      this.backgroundLoading = false
-      this.replicasLoaded = true
-    }).catch(() => {
-      this.loading = false
-      this.backgroundLoading = false
-    })
+    try {
+      let replicas = await ReplicaSource.getReplicas(options && options.skipLog)
+      this.getReplicasSuccess(replicas)
+    } finally {
+      this.getReplicasDone()
+    }
+  }
+
+  @action getReplicasSuccess(replicas: MainItem[]) {
+    this.replicasLoaded = true
+    this.replicas = replicas
+  }
+
+  @action getReplicasDone() {
+    this.loading = false
+    this.backgroundLoading = false
   }
   }
 
 
-  @action getReplicaExecutions(replicaId: string, options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
+  @action async getReplicaExecutions(replicaId: string, options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
     if (options && options.showLoading) this.executionsLoading = true
     if (options && options.showLoading) this.executionsLoading = true
 
 
-    return ReplicaSource.getReplicaExecutions(replicaId, options && options.skipLog).then(executions => {
-      let replica = this.replicas.find(replica => replica.id === replicaId)
+    try {
+      let executions = await ReplicaSource.getReplicaExecutions(replicaId, options && options.skipLog)
+      this.getReplicaExecutionsSuccess(replicaId, executions)
+    } finally {
+      runInAction(() => { this.executionsLoading = false })
+    }
+  }
 
 
-      if (replica) {
-        replica.executions = executions
-      }
+  @action getReplicaExecutionsSuccess(replicaId: string, executions: Execution[]) {
+    let replica = this.replicas.find(replica => replica.id === replicaId)
 
 
-      if (this.replicaDetails && this.replicaDetails.id === replicaId) {
-        this.replicaDetails = {
-          ...this.replicaDetails,
-          executions,
-        }
-      }
+    if (replica) {
+      replica.executions = executions
+    }
 
 
-      this.executionsLoading = false
-    }).catch(() => { this.executionsLoading = false })
+    if (this.replicaDetails && this.replicaDetails.id === replicaId) {
+      this.replicaDetails = {
+        ...this.replicaDetails,
+        executions,
+      }
+    }
   }
   }
 
 
-  @action getReplica(replicaId: string, options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
+  @action async getReplica(replicaId: string, options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
     this.detailsLoading = Boolean(options && options.showLoading)
     this.detailsLoading = Boolean(options && options.showLoading)
 
 
-    return ReplicaSource.getReplica(replicaId, options && options.skipLog).then(replica => {
-      this.detailsLoading = false
-      this.replicaDetails = replica
-    }).catch(() => {
-      this.detailsLoading = false
-    })
+    try {
+      let replica = await ReplicaSource.getReplica(replicaId, options && options.skipLog)
+      runInAction(() => { this.replicaDetails = replica })
+    } finally {
+      runInAction(() => { this.detailsLoading = false })
+    }
   }
   }
 
 
-  @action execute(replicaId: string, fields?: Field[]): Promise<void> {
-    return ReplicaSource.execute(replicaId, fields).then(execution => {
-      if (this.replicaDetails && this.replicaDetails.id === replicaId) {
-        this.replicaDetails = ReplicaStoreUtils.getNewReplica(this.replicaDetails, execution)
-      }
+  @action async execute(replicaId: string, fields?: Field[]): Promise<void> {
+    let execution = await ReplicaSource.execute(replicaId, fields)
+    this.executeSuccess(replicaId, execution)
+  }
 
 
-      let replicasItemIndex = this.replicas ? this.replicas.findIndex(r => r.id === replicaId) : -1
+  @action executeSuccess(replicaId: string, execution: Execution) {
+    if (this.replicaDetails && this.replicaDetails.id === replicaId) {
+      this.replicaDetails = ReplicaStoreUtils.getNewReplica(this.replicaDetails, execution)
+    }
 
 
-      if (replicasItemIndex > -1) {
-        const updatedReplica = ReplicaStoreUtils.getNewReplica(this.replicas[replicasItemIndex], execution)
-        this.replicas[replicasItemIndex] = updatedReplica
-      }
-    })
+    let replicasItemIndex = this.replicas ? this.replicas.findIndex(r => r.id === replicaId) : -1
+
+    if (replicasItemIndex > -1) {
+      const updatedReplica = ReplicaStoreUtils.getNewReplica(this.replicas[replicasItemIndex], execution)
+      this.replicas[replicasItemIndex] = updatedReplica
+    }
   }
   }
 
 
-  @action cancelExecution(replicaId: string, executionId: string): Promise<void> {
-    return ReplicaSource.cancelExecution(replicaId, executionId).then(() => {
-      notificationStore.alert('Cancelled', 'success')
-    })
+  async cancelExecution(replicaId: string, executionId: string): Promise<void> {
+    await ReplicaSource.cancelExecution(replicaId, executionId)
+    notificationStore.alert('Cancelled', 'success')
   }
   }
 
 
-  @action deleteExecution(replicaId: string, executionId: string): Promise<void> {
-    return ReplicaSource.deleteExecution(replicaId, executionId).then(() => {
-      let executions = []
+  async deleteExecution(replicaId: string, executionId: string): Promise<void> {
+    await ReplicaSource.deleteExecution(replicaId, executionId)
+    this.deleteExecutionSuccess(replicaId, executionId)
+  }
+
+  @action deleteExecutionSuccess(replicaId: string, executionId: string) {
+    let executions = []
 
 
-      if (this.replicaDetails && this.replicaDetails.id === replicaId) {
-        if (this.replicaDetails.executions) {
-          executions = [...this.replicaDetails.executions.filter(e => e.id !== executionId)]
-        }
+    if (this.replicaDetails && this.replicaDetails.id === replicaId) {
+      if (this.replicaDetails.executions) {
+        executions = [...this.replicaDetails.executions.filter(e => e.id !== executionId)]
+      }
 
 
-        this.replicaDetails = {
-          ...this.replicaDetails,
-          executions,
-        }
+      this.replicaDetails = {
+        ...this.replicaDetails,
+        executions,
       }
       }
-    })
+    }
   }
   }
 
 
-  @action delete(replicaId: string) {
-    return ReplicaSource.delete(replicaId).then(() => {
-      this.replicas = this.replicas.filter(r => r.id !== replicaId)
-    })
+  async delete(replicaId: string) {
+    await ReplicaSource.delete(replicaId)
+    runInAction(() => { this.replicas = this.replicas.filter(r => r.id !== replicaId) })
   }
   }
 
 
-  @action deleteDisks(replicaId: string) {
-    return ReplicaSource.deleteDisks(replicaId).then(execution => {
-      if (this.replicaDetails && this.replicaDetails.id === replicaId) {
-        this.replicaDetails = ReplicaStoreUtils.getNewReplica(this.replicaDetails, execution)
-      }
+  async deleteDisks(replicaId: string) {
+    let execution = await ReplicaSource.deleteDisks(replicaId)
+    this.deleteDisksSuccess(replicaId, execution)
+  }
 
 
-      let replicasItemIndex = this.replicas ? this.replicas.findIndex(r => r.id === replicaId) : -1
+  @action deleteDisksSuccess(replicaId: string, execution: Execution) {
+    if (this.replicaDetails && this.replicaDetails.id === replicaId) {
+      this.replicaDetails = ReplicaStoreUtils.getNewReplica(this.replicaDetails, execution)
+    }
 
 
-      if (replicasItemIndex > -1) {
-        const updatedReplica = ReplicaStoreUtils.getNewReplica(this.replicas[replicasItemIndex], execution)
-        this.replicas[replicasItemIndex] = updatedReplica
-      }
-    })
+    let replicasItemIndex = this.replicas ? this.replicas.findIndex(r => r.id === replicaId) : -1
+
+    if (replicasItemIndex > -1) {
+      const updatedReplica = ReplicaStoreUtils.getNewReplica(this.replicas[replicasItemIndex], execution)
+      this.replicas[replicasItemIndex] = updatedReplica
+    }
   }
   }
 
 
   @action clearDetails() {
   @action clearDetails() {
@@ -163,8 +182,8 @@ class ReplicaStore {
     this.replicaDetails = null
     this.replicaDetails = null
   }
   }
 
 
-  @action update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string) {
-    return ReplicaSource.update(replica, destinationEndpoint, updateData, storageConfigDefault)
+  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string) {
+    await ReplicaSource.update(replica, destinationEndpoint, updateData, storageConfigDefault)
   }
   }
 }
 }
 
 

+ 33 - 35
src/stores/ScheduleStore.js

@@ -41,57 +41,55 @@ class ScheduleStore {
   @observable scheduling: boolean = false
   @observable scheduling: boolean = false
   @observable adding: boolean = false
   @observable adding: boolean = false
 
 
-  @action scheduleMultiple(replicaId: string, schedules: Schedule[]): Promise<void> {
+  @action async scheduleMultiple(replicaId: string, schedules: Schedule[]): Promise<void> {
     this.scheduling = true
     this.scheduling = true
 
 
-    return Source.scheduleMultiple(replicaId, schedules).then((schedules: Schedule[]) => {
-      this.scheduling = false
-      this.schedules = schedules
-    }).catch(() => {
-      this.scheduling = false
-    })
+    try {
+      let scheduledSchedules: Schedule[] = await Source.scheduleMultiple(replicaId, schedules)
+      runInAction(() => { this.schedules = scheduledSchedules })
+    } finally {
+      runInAction(() => { this.scheduling = false })
+    }
   }
   }
 
 
-  @action getSchedules(replicaId: string): Promise<void> {
+  @action async getSchedules(replicaId: string): Promise<void> {
     this.loading = true
     this.loading = true
 
 
-    return Source.getSchedules(replicaId).then((schedules: Schedule[]) => {
-      this.loading = false
-      this.schedules = schedules
-    }).catch(() => {
-      this.loading = false
-    })
+    try {
+      let schedules: Schedule[] = await Source.getSchedules(replicaId)
+      runInAction(() => { this.schedules = schedules })
+    } finally {
+      runInAction(() => { this.loading = false })
+    }
   }
   }
 
 
-  getSchedulesBulk(replicaIds: string[]): Promise<void> {
-    return Promise.all(replicaIds.map(replicaId => {
-      return Source.getSchedules(replicaId, { skipLog: true }).then(schedules => {
-        return { replicaId, schedules }
-      })
-    })).then(bulkSchedules => {
-      runInAction(() => { this.bulkSchedules = bulkSchedules })
-    })
+  async getSchedulesBulk(replicaIds: string[]): Promise<void> {
+    let bulkSchedules: ScheduleBulkItem[] = await Promise.all(replicaIds.map(async replicaId => {
+      let schedules: Schedule[] = await Source.getSchedules(replicaId, { skipLog: true })
+      return { replicaId, schedules }
+    }))
+    runInAction(() => { this.bulkSchedules = bulkSchedules })
   }
   }
 
 
-  @action addSchedule(replicaId: string, schedule: Schedule): Promise<void> {
+  @action async addSchedule(replicaId: string, schedule: Schedule): Promise<void> {
     this.adding = true
     this.adding = true
 
 
-    return Source.addSchedule(replicaId, schedule).then((schedule: Schedule) => {
-      this.adding = false
-      this.schedules = [...this.schedules, schedule]
-    }).catch(() => {
-      this.adding = false
-    })
+    try {
+      let addedSchedule: Schedule = await Source.addSchedule(replicaId, schedule)
+      runInAction(() => { this.schedules = [...this.schedules, addedSchedule] })
+    } finally {
+      runInAction(() => { this.adding = false })
+    }
   }
   }
 
 
-  @action removeSchedule(replicaId: string, scheduleId: string): Promise<void> {
+  @action async removeSchedule(replicaId: string, scheduleId: string): Promise<void> {
     this.schedules = this.schedules.filter(s => s.id !== scheduleId)
     this.schedules = this.schedules.filter(s => s.id !== scheduleId)
     this.unsavedSchedules = this.unsavedSchedules.filter(s => s.id !== scheduleId)
     this.unsavedSchedules = this.unsavedSchedules.filter(s => s.id !== scheduleId)
 
 
-    return Source.removeSchedule(replicaId, scheduleId)
+    await Source.removeSchedule(replicaId, scheduleId)
   }
   }
 
 
-  @action updateSchedule(
+  @action async updateSchedule(
     replicaId: string,
     replicaId: string,
     scheduleId: string,
     scheduleId: string,
     data: Schedule,
     data: Schedule,
@@ -108,10 +106,10 @@ class ScheduleStore {
       } else {
       } else {
         this.unsavedSchedules.push({ id: scheduleId, ...data })
         this.unsavedSchedules.push({ id: scheduleId, ...data })
       }
       }
-      return Promise.resolve()
+      return
     }
     }
-
-    return Source.updateSchedule(replicaId, scheduleId, data, oldData, unsavedData).then((schedule: Schedule) => {
+    let schedule: Schedule = await Source.updateSchedule(replicaId, scheduleId, data, oldData, unsavedData)
+    runInAction(() => {
       this.schedules = this.schedules.map(s => {
       this.schedules = this.schedules.map(s => {
         if (s.id === schedule.id) {
         if (s.id === schedule.id) {
           return { ...schedule }
           return { ...schedule }

+ 121 - 111
src/stores/UserStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 import type { User, Credentials } from '../types/User'
 import type { User, Credentials } from '../types/User'
 import type { Project } from '../types/Project'
 import type { Project } from '../types/Project'
 import UserSource from '../sources/UserSource'
 import UserSource from '../sources/UserSource'
@@ -51,135 +51,137 @@ class UserStore {
     UserSource.saveDomainName(domainName)
     UserSource.saveDomainName(domainName)
   }
   }
 
 
-  @action login(creds: Credentials): Promise<void> {
+  @action async login(creds: Credentials): Promise<void> {
     this.loading = true
     this.loading = true
     this.loggedUser = null
     this.loggedUser = null
     this.loginFailedResponse = null
     this.loginFailedResponse = null
 
 
-    return UserSource.login(creds).then((auth: any) => {
+    try {
+      let auth = await UserSource.login(creds)
       this.saveDomainName(creds.domain)
       this.saveDomainName(creds.domain)
-
       this.loggedUser = { id: auth.token.user.id, email: '', name: '', project: { id: '', name: '' } }
       this.loggedUser = { id: auth.token.user.id, email: '', name: '', project: { id: '', name: '' } }
-      return this.getLoggedUserInfo()
-    }).then(() => {
-      return this.loginScoped(this.loggedUser ? this.loggedUser.project_id : '', true)
-    }).then(() => {
-      return this.isAdmin()
-    }).then(() => {
-      this.loading = false
-      this.loggedIn = true
+      await this.getLoggedUserInfo()
+      await this.loginScoped(this.loggedUser ? this.loggedUser.project_id : '', true)
+      await this.isAdmin()
+      runInAction(() => { this.loggedIn = true })
       notificationStore.alert('Signed in', 'success')
       notificationStore.alert('Signed in', 'success')
-    }).catch((reason) => {
-      this.loading = false
-      this.loginFailedResponse = reason
-    })
+    } catch (err) {
+      runInAction(() => { this.loginFailedResponse = err })
+    } finally {
+      runInAction(() => { this.loading = false })
+    }
   }
   }
 
 
-  @action loginScoped(projectId?: string, skipProjectCookie?: boolean): Promise<User> {
-    return projectStore.getProjects().then(() => {
-      let projects = projectStore.projects.filter(p => p.enabled)
-      if (projects.length === 0) {
-        return Promise.reject({ status: 500, message: 'There are no projects assigned to user.' })
-      }
+  async loginScoped(projectId?: string, skipProjectCookie?: boolean): Promise<User> {
+    await projectStore.getProjects()
+    let projects = projectStore.projects.filter(p => p.enabled)
+    if (projects.length === 0) {
+      return Promise.reject({ status: 500, message: 'There are no projects assigned to user.' })
+    }
 
 
-      let project = projects.find(p => p.id === projectId)
-      let id = (project && project.id) || projects[0].id
-      return UserSource.loginScoped(id, Boolean(id && skipProjectCookie))
-    }).then((user: User) => {
+    let project = projects.find(p => p.id === projectId)
+    let id = (project && project.id) || projects[0].id
+    let user: User = await UserSource.loginScoped(id, Boolean(id && skipProjectCookie))
+    runInAction(() => {
       if (!this.loggedUser) {
       if (!this.loggedUser) {
-        return Promise.reject('No Logged in user')
+        throw new Error('No Logged in user')
       }
       }
       this.loggedUser.scoped = true
       this.loggedUser.scoped = true
       this.loggedUser.project = user.project
       this.loggedUser.project = user.project
-      return this.loggedUser
     })
     })
+    if (!this.loggedUser) {
+      throw new Error('No Logged in user')
+    }
+    return this.loggedUser
   }
   }
 
 
-  @action getLoggedUserInfo(): Promise<void> {
+  async getLoggedUserInfo(): Promise<void> {
     if (!this.loggedUser) {
     if (!this.loggedUser) {
-      return Promise.reject('No logged-in user')
+      throw new Error('No logged-in user')
     }
     }
 
 
-    return UserSource.getUserInfo(this.loggedUser.id).then((userData: User) => {
-      this.loggedUser = { ...this.loggedUser, ...userData, isAdmin: false }
-    })
+    let userData: User = await UserSource.getUserInfo(this.loggedUser.id)
+    runInAction(() => { this.loggedUser = { ...this.loggedUser, ...userData, isAdmin: false } })
   }
   }
 
 
-  @action tokenLogin(): Promise<void> {
+  @action async tokenLogin(): Promise<void> {
     this.loggedUser = null
     this.loggedUser = null
     this.loading = true
     this.loading = true
 
 
-    return UserSource.tokenLogin().then(user => {
-      this.loggedUser = { ...this.loggedUser, ...user }
+    try {
+      let user = await UserSource.tokenLogin()
+      runInAction(() => { this.loggedUser = { ...this.loggedUser, ...user } })
       notificationStore.alert('Signed in', 'success')
       notificationStore.alert('Signed in', 'success')
-      return this.getLoggedUserInfo()
-    }).then(() => {
-      return this.isAdmin()
-    }).then(() => {
-      this.loading = false
-      this.loggedIn = true
-    }).catch(() => {
+      await this.getLoggedUserInfo()
+      await this.isAdmin()
+      runInAction(() => { this.loggedIn = true })
+    } finally {
       this.loading = false
       this.loading = false
-    })
+    }
   }
   }
 
 
-  @action switchProject(projectId: string): Promise<void> {
-    return UserSource.switchProject().then(() => {
-      return this.loginScoped(projectId)
-    }).then(() => {
-      return this.isAdmin()
-    }).catch(reason => {
-      console.error('Error switching projects', reason)
+  async switchProject(projectId: string): Promise<void> {
+    try {
+      await UserSource.switchProject()
+      await this.loginScoped(projectId)
+      await this.isAdmin()
+    } catch (err) {
+      console.error('Error switching projects', err)
       notificationStore.alert('Error switching projects')
       notificationStore.alert('Error switching projects')
       this.logout()
       this.logout()
-    })
+    }
   }
   }
 
 
-  @action logout(): Promise<void> {
+  @action async logout(): Promise<void> {
     this.loggedIn = false
     this.loggedIn = false
 
 
-    return UserSource.logout().catch(reason => {
-      console.log('Error logging out', reason)
+    try {
+      await UserSource.logout()
+    } catch (err) {
+      console.log('Error logging out', err)
       notificationStore.alert('Error logging out')
       notificationStore.alert('Error logging out')
-    })
+    }
   }
   }
 
 
-  @action getAllUsers(options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
+  @action async getAllUsers(options?: { showLoading?: boolean, skipLog?: boolean }): Promise<void> {
     if (options && options.showLoading) this.allUsersLoading = true
     if (options && options.showLoading) this.allUsersLoading = true
 
 
-    return UserSource.getAllUsers(options && options.skipLog).then(users => {
-      this.users = users
-      this.allUsersLoading = false
-    }).catch(() => {
-      this.allUsersLoading = false
-    })
+    try {
+      let users = await UserSource.getAllUsers(options && options.skipLog)
+      runInAction(() => { this.users = users })
+    } finally {
+      runInAction(() => { this.allUsersLoading = false })
+    }
   }
   }
 
 
-  @action getUserInfo(userId: string): Promise<void> {
+  @action async getUserInfo(userId: string): Promise<void> {
     this.userDetailsLoading = true
     this.userDetailsLoading = true
 
 
-    return UserSource.getUserInfo(userId).then(user => {
-      this.userDetails = user
-      this.userDetailsLoading = false
-    }).catch(() => {
-      this.userDetailsLoading = false
-    })
+    try {
+      let user = await UserSource.getUserInfo(userId)
+      runInAction(() => { this.userDetails = user })
+    } finally {
+      runInAction(() => { this.userDetailsLoading = false })
+    }
   }
   }
 
 
-  @action isAdmin(): Promise<void> {
+  @action async isAdmin(): Promise<void> {
     if (!this.loggedUser) {
     if (!this.loggedUser) {
-      return Promise.resolve()
+      return
     }
     }
     this.loggedUser.isAdmin = false
     this.loggedUser.isAdmin = false
-    return UserSource.isAdmin(this.loggedUser.id).then(isAdmin => {
-      if (this.loggedUser) {
-        this.loggedUser.isAdmin = isAdmin
-      }
-    }).catch(() => {
+    try {
+      let isAdmin = await UserSource.isAdmin(this.loggedUser.id)
+      runInAction(() => {
+        if (this.loggedUser) {
+          this.loggedUser.isAdmin = isAdmin
+        }
+      })
+    } catch (err) {
       if (window.location.href.indexOf(`${DomUtils.urlHashPrefix}project`) > -1 || window.location.href.indexOf(`${DomUtils.urlHashPrefix}user`) > -1) {
       if (window.location.href.indexOf(`${DomUtils.urlHashPrefix}project`) > -1 || window.location.href.indexOf(`${DomUtils.urlHashPrefix}user`) > -1) {
         window.location.href = `${DomUtils.urlHashPrefix}`
         window.location.href = `${DomUtils.urlHashPrefix}`
       }
       }
-    })
+    }
   }
   }
 
 
   @action clearUserDetails() {
   @action clearUserDetails() {
@@ -187,62 +189,70 @@ class UserStore {
     this.userDetails = null
     this.userDetails = null
   }
   }
 
 
-  @action update(userId: string, user: User): Promise<void> {
+  @action async update(userId: string, user: User): Promise<void> {
     this.updating = true
     this.updating = true
 
 
-    return UserSource.update(userId, user, this.userDetails).then((user: User) => {
-      this.userDetails = user
-      this.updating = false
-      if (this.loggedUser && this.loggedUser.id === userId) {
-        this.loggedUser.name = user.name
-      }
-    }).catch(() => {
-      this.updating = false
-    })
+    try {
+      let updatedUser: User = await UserSource.update(userId, user, this.userDetails)
+      runInAction(() => {
+        this.userDetails = updatedUser
+        if (this.loggedUser && this.loggedUser.id === userId) {
+          this.loggedUser.name = user.name
+        }
+      })
+    } finally {
+      runInAction(() => { this.updating = false })
+    }
   }
   }
 
 
-  @action assignUserToProject(userId: string, projectId: string): Promise<void> {
+  @action async assignUserToProject(userId: string, projectId: string): Promise<void> {
     this.updating = true
     this.updating = true
 
 
-    return UserSource.assignUserToProject(userId, projectId).then(() => {
-      this.updating = false
-    }).catch(() => { this.updating = false })
+    try {
+      await UserSource.assignUserToProject(userId, projectId)
+    } finally {
+      runInAction(() => { this.updating = false })
+    }
   }
   }
 
 
-  @action assignUserToProjectWithRole(userId: string, projectId: string, roleId: string): Promise<void> {
-    return UserSource.assignUserToProjectWithRole(userId, projectId, roleId)
+  async assignUserToProjectWithRole(userId: string, projectId: string, roleId: string): Promise<void> {
+    await UserSource.assignUserToProjectWithRole(userId, projectId, roleId)
   }
   }
 
 
-  @action add(user: User): Promise<?User> {
+  @action async add(user: User): Promise<?User> {
     this.updating = true
     this.updating = true
 
 
-    return UserSource.add(user).then((user: User) => {
-      if (!this.users.find(u => u.id === user.id)) {
+    try {
+      let addedUser: User = await UserSource.add(user)
+      if (this.users.find(u => u.id === addedUser.id)) {
+        return null
+      }
+      runInAction(() => {
         this.users = [
         this.users = [
           ...this.users,
           ...this.users,
-          user,
+          addedUser,
         ]
         ]
         this.users.sort((a, b) => a.name.localeCompare(b.name))
         this.users.sort((a, b) => a.name.localeCompare(b.name))
-      }
-      this.updating = false
-      return user
-    }).catch((ex) => {
-      console.error(ex)
-      this.updating = false
+      })
+      return addedUser
+    } catch (err) {
+      console.error(err)
       return null
       return null
-    })
+    } finally {
+      runInAction(() => { this.updating = false })
+    }
   }
   }
 
 
-  @action delete(userId: string): Promise<void> {
-    return UserSource.delete(userId).then(() => {
+  async delete(userId: string): Promise<void> {
+    await UserSource.delete(userId)
+    runInAction(() => {
       this.users = this.users.filter(u => u.id === userId)
       this.users = this.users.filter(u => u.id === userId)
     })
     })
   }
   }
 
 
-  @action getProjects(userId: string): Promise<void> {
-    return UserSource.getProjects(userId).then((projects: Project[]) => {
-      this.projects = projects
-    })
+  async getProjects(userId: string): Promise<void> {
+    let projects: Project[] = await UserSource.getProjects(userId)
+    runInAction(() => { this.projects = projects })
   }
   }
 
 
   @action clearProjects() {
   @action clearProjects() {

+ 18 - 17
src/stores/WizardStore.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 // @flow
 // @flow
 
 
-import { observable, action } from 'mobx'
+import { observable, action, runInAction } from 'mobx'
 
 
 import type { WizardData, WizardPage } from '../types/WizardData'
 import type { WizardData, WizardPage } from '../types/WizardData'
 import type { MainItem } from '../types/MainItem'
 import type { MainItem } from '../types/MainItem'
@@ -137,30 +137,31 @@ class WizardStore {
     this.schedules = this.schedules.filter(s => s.id !== scheduleId)
     this.schedules = this.schedules.filter(s => s.id !== scheduleId)
   }
   }
 
 
-  @action create(type: string, data: WizardData, storageMap: StorageMap[]): Promise<void> {
+  @action async create(type: string, data: WizardData, storageMap: StorageMap[]): Promise<void> {
     this.creatingItem = true
     this.creatingItem = true
 
 
-    return Source.create(type, data, storageMap).then((item: MainItem) => {
-      this.createdItem = item
-      this.creatingItem = false
-    }).catch(() => {
-      this.creatingItem = false
-      return Promise.reject()
-    })
+    try {
+      let item: MainItem = await Source.create(type, data, storageMap)
+      runInAction(() => { this.createdItem = item })
+    } catch (err) {
+      throw err
+    } finally {
+      runInAction(() => { this.creatingItem = false })
+    }
   }
   }
 
 
-  @action createMultiple(type: string, data: WizardData, storageMap: StorageMap[]): Promise<void> {
+  @action async createMultiple(type: string, data: WizardData, storageMap: StorageMap[]): Promise<void> {
     this.creatingItems = true
     this.creatingItems = true
 
 
-    return Source.createMultiple(type, data, storageMap).then((items: MainItem[]) => {
-      this.createdItems = items
-      this.creatingItems = false
-    }).catch(() => {
-      this.creatingItems = false
-    })
+    try {
+      let items: MainItem[] = await Source.createMultiple(type, data, storageMap)
+      runInAction(() => { this.createdItems = items })
+    } finally {
+      runInAction(() => { this.creatingItems = false })
+    }
   }
   }
 
 
-  @action setPermalink(data: WizardData) {
+  setPermalink(data: WizardData) {
     Source.setPermalink(data)
     Source.setPermalink(data)
   }
   }
 
 

+ 1 - 0
src/types/User.js

@@ -28,6 +28,7 @@ export type User = {
   domain_id?: string,
   domain_id?: string,
   isAdmin?: boolean,
   isAdmin?: boolean,
   password?: string,
   password?: string,
+  extra?: any,
 }
 }
 
 
 export type Credentials = {
 export type Credentials = {

+ 3 - 4
src/utils/Config.js

@@ -7,10 +7,9 @@ import type { Config } from '../types/Config'
 class ConfigLoader {
 class ConfigLoader {
   config: Config
   config: Config
 
 
-  load() {
-    return apiCaller.get('/config').then(res => {
-      this.config = res.data
-    })
+  async load() {
+    let res = await apiCaller.get('/config')
+    this.config = res.data
   }
   }
 }
 }
 
 

+ 7 - 6
src/utils/ObjectUtils.js

@@ -55,19 +55,20 @@ class ObjectUtils {
     return result
     return result
   }
   }
 
 
-  static waitFor(predicate: () => boolean, timeoutMs?: number = 15000): Promise<void> {
+  static async waitFor(predicate: () => boolean, timeoutMs?: number = 15000) {
     let wait = (ms: number) => new Promise(resolve => { setTimeout(() => { resolve() }, ms) })
     let wait = (ms: number) => new Promise(resolve => { setTimeout(() => { resolve() }, ms) })
     let startTime = new Date().getTime()
     let startTime = new Date().getTime()
-    let testLoop = (): Promise<void> => {
+    let testLoop = async () => {
       if (predicate()) {
       if (predicate()) {
-        return Promise.resolve()
+        return
       }
       }
       if (new Date().getTime() - startTime > timeoutMs) {
       if (new Date().getTime() - startTime > timeoutMs) {
-        return Promise.reject(`Timeout: waiting for more than ${timeoutMs} ms`)
+        throw new Error(`Timeout: waiting for more than ${timeoutMs} ms`)
       }
       }
-      return wait(1000).then(() => testLoop())
+      await wait(1000)
+      await testLoop()
     }
     }
-    return testLoop()
+    await testLoop()
   }
   }
 }
 }