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

Add Flow support to all of app's source classes

Sergiu Miclea 8 лет назад
Родитель
Сommit
be77c7f60f

+ 2 - 0
src/sources/EndpointSource.js

@@ -120,7 +120,9 @@ class EdnpointSource {
       let parsedEndpoint = SchemaParser.fieldsToPayload(endpoint)
       let parsedEndpoint = SchemaParser.fieldsToPayload(endpoint)
 
 
       if (parsedEndpoint.connection_info && parsedEndpoint.connection_info.secret_ref) {
       if (parsedEndpoint.connection_info && parsedEndpoint.connection_info.secret_ref) {
+        // $FlowIgnore
         let uuidIndex = parsedEndpoint.connection_info.secret_ref.lastIndexOf('/')
         let uuidIndex = parsedEndpoint.connection_info.secret_ref.lastIndexOf('/')
+        // $FlowIgnore
         let uuid = parsedEndpoint.connection_info.secret_ref.substr(uuidIndex + 1)
         let uuid = parsedEndpoint.connection_info.secret_ref.substr(uuidIndex + 1)
 
 
         Api.sendAjaxRequest({
         Api.sendAjaxRequest({

+ 7 - 4
src/sources/InstanceSource.js

@@ -12,16 +12,19 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
+import type { Instance } from '../types/Instance'
 
 
 import { servicesUrl, wizardConfig } from '../config'
 import { servicesUrl, wizardConfig } from '../config'
 
 
 class InstanceSource {
 class InstanceSource {
-  static loadInstances(endpointId, searchText, lastInstanceId) {
+  static loadInstances(endpointId: string, searchText?: string, lastInstanceId?: string): Promise<Instance[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
-      let projectId = cookie.get('projectId')
+      let projectId = cookie.get('projectId') || 'undefined'
       let url = `${servicesUrl.coriolis}/${projectId}/endpoints/${endpointId}/instances?limit=${wizardConfig.instancesItemsPerPage + 1}`
       let url = `${servicesUrl.coriolis}/${projectId}/endpoints/${endpointId}/instances?limit=${wizardConfig.instancesItemsPerPage + 1}`
 
 
       if (searchText) {
       if (searchText) {
@@ -41,9 +44,9 @@ class InstanceSource {
     })
     })
   }
   }
 
 
-  static loadInstanceDetails(endpointId, instanceName) {
+  static loadInstanceDetails(endpointId: string, instanceName: string): Promise<Instance> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
-      let projectId = cookie.get('projectId')
+      let projectId = cookie.get('projectId') || 'undefined'
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: `${servicesUrl.coriolis}/${projectId}/endpoints/${endpointId}/instances/${btoa(instanceName)}`,
         url: `${servicesUrl.coriolis}/${projectId}/endpoints/${endpointId}/instances/${btoa(instanceName)}`,

+ 14 - 10
src/sources/MigrationSource.js

@@ -12,10 +12,14 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 import moment from 'moment'
 import moment from 'moment'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
+import type { MainItem } from '../types/MainItem'
+import type { Field } from '../types/Field'
 
 
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
 
 
@@ -46,9 +50,9 @@ class MigrationSourceUtils {
 }
 }
 
 
 class MigrationSource {
 class MigrationSource {
-  static getMigrations() {
+  static getMigrations(): Promise<MainItem[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
-      let projectId = cookie.get('projectId')
+      let projectId = cookie.get('projectId') || 'null'
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: `${servicesUrl.coriolis}/${projectId}/migrations/detail`,
         url: `${servicesUrl.coriolis}/${projectId}/migrations/detail`,
         method: 'GET',
         method: 'GET',
@@ -60,9 +64,9 @@ class MigrationSource {
     })
     })
   }
   }
 
 
-  static getMigration(migrationId) {
+  static getMigration(migrationId: string): Promise<MainItem> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
-      let projectId = cookie.get('projectId')
+      let projectId = cookie.get('projectId') || 'null'
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: `${servicesUrl.coriolis}/${projectId}/migrations/${migrationId}`,
         url: `${servicesUrl.coriolis}/${projectId}/migrations/${migrationId}`,
@@ -75,9 +79,9 @@ class MigrationSource {
     })
     })
   }
   }
 
 
-  static cancel(migrationId) {
+  static cancel(migrationId: string): Promise<string> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
-      let projectId = cookie.get('projectId')
+      let projectId = cookie.get('projectId') || 'null'
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: `${servicesUrl.coriolis}/${projectId}/migrations/${migrationId}/actions`,
         url: `${servicesUrl.coriolis}/${projectId}/migrations/${migrationId}/actions`,
@@ -89,17 +93,17 @@ class MigrationSource {
     })
     })
   }
   }
 
 
-  static delete(migrationId) {
+  static delete(migrationId: string): Promise<string> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/migrations/${migrationId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/migrations/${migrationId}`,
         method: 'DELETE',
         method: 'DELETE',
       }).then(() => { resolve(migrationId) }, reject).catch(reject)
       }).then(() => { resolve(migrationId) }, reject).catch(reject)
     })
     })
   }
   }
 
 
-  static migrateReplica(replicaId, options) {
+  static migrateReplica(replicaId: string, options: Field[]): Promise<MainItem> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       let payload = {
       let payload = {
@@ -112,7 +116,7 @@ class MigrationSource {
       })
       })
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/migrations`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/migrations`,
         method: 'POST',
         method: 'POST',
         data: payload,
         data: payload,
       }).then(response => {
       }).then(response => {

+ 5 - 2
src/sources/NetworkSource.js

@@ -12,17 +12,20 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
+import type { Network } from '../types/Network'
 
 
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
 
 
 class NetworkSource {
 class NetworkSource {
-  static loadNetworks(enpointId, environment) {
+  static loadNetworks(enpointId: string, environment: ?{ [string]: mixed }): Promise<Network[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
-      let url = `${servicesUrl.coriolis}/${projectId}/endpoints/${enpointId}/networks`
+      let url = `${servicesUrl.coriolis}/${projectId || 'null'}/endpoints/${enpointId}/networks`
       if (environment) {
       if (environment) {
         url = `${url}?env=${btoa(JSON.stringify(environment))}`
         url = `${url}?env=${btoa(JSON.stringify(environment))}`
       }
       }

+ 8 - 4
src/sources/NotificationSource.js

@@ -12,12 +12,16 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
+import type { NotificationItem } from '../types/NotificationItem'
+
 class NotificationSource {
 class NotificationSource {
-  static notify(message, level, options) {
+  static notify(message: string, level?: $PropertyType<NotificationItem, 'level'>, options?: $PropertyType<NotificationItem, 'options'>): Promise<NotificationItem> {
     return new Promise(resolve => {
     return new Promise(resolve => {
       let notifications = JSON.parse(localStorage.getItem('notifications') || '[]')
       let notifications = JSON.parse(localStorage.getItem('notifications') || '[]')
       let newItem = {
       let newItem = {
-        id: new Date().getTime(),
+        id: new Date().getTime().toString(),
         message,
         message,
         level,
         level,
         options,
         options,
@@ -28,13 +32,13 @@ class NotificationSource {
     })
     })
   }
   }
 
 
-  static loadNotifications() {
+  static loadNotifications(): Promise<NotificationItem[]> {
     return new Promise(resolve => {
     return new Promise(resolve => {
       resolve(JSON.parse(localStorage.getItem('notifications') || '[]'))
       resolve(JSON.parse(localStorage.getItem('notifications') || '[]'))
     })
     })
   }
   }
 
 
-  static clearNotifications() {
+  static clearNotifications(): Promise<void> {
     return new Promise(resolve => {
     return new Promise(resolve => {
       localStorage.setItem('notifications', '[]')
       localStorage.setItem('notifications', '[]')
       resolve()
       resolve()

+ 4 - 1
src/sources/ProjectSource.js

@@ -12,12 +12,15 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
 
 
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
+import type { Project } from '../types/Project'
 
 
 class ProjectsSource {
 class ProjectsSource {
-  static getProjects() {
+  static getProjects(): Promise<Project[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: servicesUrl.projects,
         url: servicesUrl.projects,

+ 10 - 6
src/sources/ProviderSource.js

@@ -12,20 +12,24 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
 
 
 import { servicesUrl, providerTypes } from '../config'
 import { servicesUrl, providerTypes } from '../config'
 import { SchemaParser } from './Schemas'
 import { SchemaParser } from './Schemas'
+import type { Field } from '../types/Field'
+import type { Providers } from '../types/Providers'
 
 
 class ProviderSource {
 class ProviderSource {
-  static getConnectionInfoSchema(providerName) {
+  static getConnectionInfoSchema(providerName: string): Promise<Field[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/providers/${providerName}/schemas/${providerTypes.CONNECTION}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/providers/${providerName}/schemas/${providerTypes.CONNECTION}`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         let schema = response.data.schemas.connection_info_schema
         let schema = response.data.schemas.connection_info_schema
@@ -35,12 +39,12 @@ class ProviderSource {
     })
     })
   }
   }
 
 
-  static loadProviders() {
+  static loadProviders(): Promise<Providers> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/providers`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/providers`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         resolve(response.data.providers)
         resolve(response.data.providers)
@@ -48,13 +52,13 @@ class ProviderSource {
     })
     })
   }
   }
 
 
-  static loadOptionsSchema(providerName, schemaType) {
+  static loadOptionsSchema(providerName: string, schemaType: string): Promise<Field[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       let schemaTypeInt = schemaType === 'migration' ? providerTypes.TARGET_MIGRATION : providerTypes.TARGET_REPLICA
       let schemaTypeInt = schemaType === 'migration' ? providerTypes.TARGET_MIGRATION : providerTypes.TARGET_REPLICA
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/providers/${providerName}/schemas/${schemaTypeInt}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/providers/${providerName}/schemas/${schemaTypeInt}`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         let schema = response.data.schemas.destination_environment_schema
         let schema = response.data.schemas.destination_environment_schema

+ 23 - 18
src/sources/ReplicaSource.js

@@ -12,12 +12,17 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 import moment from 'moment'
 import moment from 'moment'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
 
 
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
+import type { MainItem } from '../types/MainItem'
+import type { Execution } from '../types/Execution'
+import type { Field } from '../types/Field'
 
 
 class ReplicaSourceUtils {
 class ReplicaSourceUtils {
   static filterDeletedExecutionsInReplicas(replicas) {
   static filterDeletedExecutionsInReplicas(replicas) {
@@ -79,11 +84,11 @@ class ReplicaSourceUtils {
 }
 }
 
 
 class ReplicaSource {
 class ReplicaSource {
-  static getReplicas() {
+  static getReplicas(): Promise<MainItem[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/detail`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/detail`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         let replicas = response.data.replicas
         let replicas = response.data.replicas
@@ -94,11 +99,11 @@ class ReplicaSource {
     })
     })
   }
   }
 
 
-  static getReplicaExecutions(replicaId) {
+  static getReplicaExecutions(replicaId: string): Promise<Execution[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/executions/detail`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/executions/detail`,
         method: 'GET',
         method: 'GET',
       }).then((response) => {
       }).then((response) => {
         let executions = response.data.executions
         let executions = response.data.executions
@@ -109,12 +114,12 @@ class ReplicaSource {
     })
     })
   }
   }
 
 
-  static getReplica(replicaId) {
+  static getReplica(replicaId: string): Promise<MainItem> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         let replica = response.data.replica
         let replica = response.data.replica
@@ -125,7 +130,7 @@ class ReplicaSource {
     })
     })
   }
   }
 
 
-  static execute(replicaId, fields) {
+  static execute(replicaId: string, fields?: Field[]): Promise<Execution> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let payload = { execution: { shutdown_instances: false } }
       let payload = { execution: { shutdown_instances: false } }
       if (fields) {
       if (fields) {
@@ -136,7 +141,7 @@ class ReplicaSource {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/executions`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/executions`,
         method: 'POST',
         method: 'POST',
         data: payload,
         data: payload,
       }).then((response) => {
       }).then((response) => {
@@ -147,50 +152,50 @@ class ReplicaSource {
     })
     })
   }
   }
 
 
-  static cancelExecution(replicaId, executionId) {
+  static cancelExecution(replicaId: string, executionId: string): Promise<string> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/executions/${executionId}/actions`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/executions/${executionId}/actions`,
         method: 'POST',
         method: 'POST',
         data: { cancel: null },
         data: { cancel: null },
       }).then(() => {
       }).then(() => {
-        resolve(replicaId, executionId)
+        resolve(replicaId)
       }, reject).catch(reject)
       }, reject).catch(reject)
     })
     })
   }
   }
 
 
-  static deleteExecution(replicaId, executionId) {
+  static deleteExecution(replicaId: string, executionId: string): Promise<string> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/executions/${executionId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/executions/${executionId}`,
         method: 'DELETE',
         method: 'DELETE',
       }).then(() => {
       }).then(() => {
-        resolve(replicaId, executionId)
+        resolve(replicaId)
       }, reject).catch(reject)
       }, reject).catch(reject)
     })
     })
   }
   }
 
 
-  static delete(replicaId) {
+  static delete(replicaId: string): Promise<string> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}`,
         method: 'DELETE',
         method: 'DELETE',
       }).then(() => { resolve(replicaId) }, reject).catch(reject)
       }).then(() => { resolve(replicaId) }, reject).catch(reject)
     })
     })
   }
   }
 
 
-  static deleteDisks(replicaId) {
+  static deleteDisks(replicaId: string): Promise<Execution> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/actions`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/actions`,
         method: 'POST',
         method: 'POST',
         data: { 'delete-disks': null },
         data: { 'delete-disks': null },
       }).then(response => {
       }).then(response => {

+ 28 - 12
src/sources/ScheduleSource.js

@@ -12,29 +12,35 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 import moment from 'moment'
 import moment from 'moment'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
 import DateUtils from '../utils/DateUtils'
 import DateUtils from '../utils/DateUtils'
+import type { Schedule } from '../types/Schedule'
 
 
 class ScheduleSource {
 class ScheduleSource {
-  static scheduleSinge(replicaId, scheduleData) {
+  static scheduleSinge(replicaId: string, scheduleData: Schedule): Promise<Schedule> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       let payload = {
       let payload = {
         schedule: {},
         schedule: {},
+        expiration_date: null,
         enabled: scheduleData.enabled === null || scheduleData.enabled === undefined ? false : scheduleData.enabled,
         enabled: scheduleData.enabled === null || scheduleData.enabled === undefined ? false : scheduleData.enabled,
         shutdown_instance: scheduleData.shutdown_instances === null || scheduleData.shutdown_instances === undefined ? false : scheduleData.shutdown_instances,
         shutdown_instance: scheduleData.shutdown_instances === null || scheduleData.shutdown_instances === undefined ? false : scheduleData.shutdown_instances,
       }
       }
 
 
       if (scheduleData.expiration_date) {
       if (scheduleData.expiration_date) {
+        // $FlowIssue
         payload.expiration_date = moment(scheduleData.expiration_date).toISOString()
         payload.expiration_date = moment(scheduleData.expiration_date).toISOString()
       }
       }
 
 
       if (scheduleData.schedule !== null && scheduleData.schedule !== undefined) {
       if (scheduleData.schedule !== null && scheduleData.schedule !== undefined) {
         Object.keys(scheduleData.schedule).forEach(prop => {
         Object.keys(scheduleData.schedule).forEach(prop => {
+          // $FlowIssue
           if (scheduleData.schedule[prop] !== null && scheduleData.schedule[prop] !== undefined) {
           if (scheduleData.schedule[prop] !== null && scheduleData.schedule[prop] !== undefined) {
             payload.schedule[prop] = scheduleData.schedule[prop]
             payload.schedule[prop] = scheduleData.schedule[prop]
           }
           }
@@ -42,7 +48,7 @@ class ScheduleSource {
       }
       }
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/schedules`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/schedules`,
         method: 'POST',
         method: 'POST',
         data: payload,
         data: payload,
       }).then(response => {
       }).then(response => {
@@ -51,7 +57,7 @@ class ScheduleSource {
     })
     })
   }
   }
 
 
-  static scheduleMultiple(replicaId, schedules) {
+  static scheduleMultiple(replicaId: string, schedules: Schedule[]): Promise<Schedule[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let createdSchedules = []
       let createdSchedules = []
       let count = 0
       let count = 0
@@ -71,12 +77,12 @@ class ScheduleSource {
     })
     })
   }
   }
 
 
-  static getSchedules(replicaId) {
+  static getSchedules(replicaId: string): Promise<Schedule[]> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/schedules`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/schedules`,
         method: 'GET',
         method: 'GET',
       }).then(response => {
       }).then(response => {
         let schedules = [...response.data.schedules]
         let schedules = [...response.data.schedules]
@@ -96,7 +102,7 @@ class ScheduleSource {
     })
     })
   }
   }
 
 
-  static addSchedule(replicaId, schedule) {
+  static addSchedule(replicaId: string, schedule: Schedule): Promise<Schedule> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       let payload = {
       let payload = {
@@ -108,7 +114,7 @@ class ScheduleSource {
       }
       }
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/schedules`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/schedules`,
         method: 'POST',
         method: 'POST',
         data: payload,
         data: payload,
       }).then(response => {
       }).then(response => {
@@ -117,17 +123,23 @@ class ScheduleSource {
     })
     })
   }
   }
 
 
-  static removeSchedule(replicaId, scheduleId) {
+  static removeSchedule(replicaId: string, scheduleId: string): Promise<void> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/schedules/${scheduleId}`,
         method: 'DELETE',
         method: 'DELETE',
       }).then(resolve, reject).catch(reject)
       }).then(resolve, reject).catch(reject)
     })
     })
   }
   }
 
 
-  static updateSchedule(replicaId, scheduleId, scheduleData, scheduleOldData, unsavedData) {
+  static updateSchedule(
+    replicaId: string,
+    scheduleId: string,
+    scheduleData: Schedule,
+    scheduleOldData: ?Schedule,
+    unsavedData: ?Schedule
+  ): Promise<Schedule> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       let projectId = cookie.get('projectId')
       let projectId = cookie.get('projectId')
       let payload = {}
       let payload = {}
@@ -141,8 +153,12 @@ class ScheduleSource {
         payload.expiration_date = moment(unsavedData.expiration_date).toISOString()
         payload.expiration_date = moment(unsavedData.expiration_date).toISOString()
       }
       }
       if (unsavedData && unsavedData.schedule !== null && unsavedData.schedule !== undefined && Object.keys(unsavedData.schedule).length) {
       if (unsavedData && unsavedData.schedule !== null && unsavedData.schedule !== undefined && Object.keys(unsavedData.schedule).length) {
-        payload.schedule = { ...scheduleOldData.schedule }
+        if (scheduleOldData) {
+          payload.schedule = { ...scheduleOldData.schedule }
+        }
+        // $FlowIssue
         Object.keys(unsavedData.schedule).forEach(prop => {
         Object.keys(unsavedData.schedule).forEach(prop => {
+          // $FlowIssue
           if (unsavedData.schedule[prop] !== null && unsavedData.schedule[prop] !== undefined) {
           if (unsavedData.schedule[prop] !== null && unsavedData.schedule[prop] !== undefined) {
             payload.schedule[prop] = unsavedData.schedule[prop]
             payload.schedule[prop] = unsavedData.schedule[prop]
           } else {
           } else {
@@ -152,7 +168,7 @@ class ScheduleSource {
       }
       }
 
 
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
-        url: `${servicesUrl.coriolis}/${projectId}/replicas/${replicaId}/schedules/${scheduleId}`,
+        url: `${servicesUrl.coriolis}/${projectId || 'null'}/replicas/${replicaId}/schedules/${scheduleId}`,
         method: 'PUT',
         method: 'PUT',
         data: payload,
         data: payload,
       }).then(response => {
       }).then(response => {

+ 5 - 3
src/sources/Schemas.js

@@ -12,13 +12,15 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import { SchemaPlugin } from '../plugins/endpoint'
 import { SchemaPlugin } from '../plugins/endpoint'
 import { defaultSchemaToFields } from '../plugins/endpoint/default/SchemaPlugin'
 import { defaultSchemaToFields } from '../plugins/endpoint/default/SchemaPlugin'
 
 
 class SchemaParser {
 class SchemaParser {
   static storedConnectionsSchemas = {}
   static storedConnectionsSchemas = {}
 
 
-  static connectionSchemaToFields(provider, schema) {
+  static connectionSchemaToFields(provider: string, schema: { [string]: any }) {
     if (!this.storedConnectionsSchemas[provider]) {
     if (!this.storedConnectionsSchemas[provider]) {
       this.storedConnectionsSchemas[provider] = schema
       this.storedConnectionsSchemas[provider] = schema
     }
     }
@@ -29,7 +31,7 @@ class SchemaParser {
     return fields
     return fields
   }
   }
 
 
-  static optionsSchemaToFields(provider, schema) {
+  static optionsSchemaToFields(provider: string, schema: { [string]: any }) {
     let fields = defaultSchemaToFields(schema.oneOf[0])
     let fields = defaultSchemaToFields(schema.oneOf[0])
     fields.sort((a, b) => {
     fields.sort((a, b) => {
       if (a.required && !b.required) {
       if (a.required && !b.required) {
@@ -45,7 +47,7 @@ class SchemaParser {
     return fields
     return fields
   }
   }
 
 
-  static fieldsToPayload(data) {
+  static fieldsToPayload(data: { [string]: any }) {
     let storedSchema = this.storedConnectionsSchemas[data.type] || this.storedConnectionsSchemas.general
     let storedSchema = this.storedConnectionsSchemas[data.type] || this.storedConnectionsSchemas.general
     let parsers = SchemaPlugin[data.type] || SchemaPlugin.default
     let parsers = SchemaPlugin[data.type] || SchemaPlugin.default
     let payload = parsers.parseFieldsToPayload(data, storedSchema)
     let payload = parsers.parseFieldsToPayload(data, storedSchema)

+ 10 - 7
src/sources/UserSource.js

@@ -12,17 +12,20 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import cookie from 'js-cookie'
 import cookie from 'js-cookie'
 
 
 import Api from '../utils/ApiCaller'
 import Api from '../utils/ApiCaller'
-
 import { servicesUrl } from '../config'
 import { servicesUrl } from '../config'
+import type { Credentials, User } from '../types/User'
 
 
 class UserModel {
 class UserModel {
   static parseUserData(response) {
   static parseUserData(response) {
     let data = {
     let data = {
       id: response.data.token.user.id,
       id: response.data.token.user.id,
       name: response.data.token.user.name,
       name: response.data.token.user.name,
+      email: response.data.token.user.email,
       project: response.data.token.project,
       project: response.data.token.project,
     }
     }
 
 
@@ -31,7 +34,7 @@ class UserModel {
 }
 }
 
 
 class UserSource {
 class UserSource {
-  static login(userData) {
+  static login(userData: Credentials): Promise<User> {
     let auth = {
     let auth = {
       auth: {
       auth: {
         identity: {
         identity: {
@@ -64,7 +67,7 @@ class UserSource {
     })
     })
   }
   }
 
 
-  static loginScoped(projectId, skipCookie) {
+  static 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')
 
 
@@ -110,7 +113,7 @@ class UserSource {
     })
     })
   }
   }
 
 
-  static tokenLogin() {
+  static 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) {
@@ -144,7 +147,7 @@ class UserSource {
     })
     })
   }
   }
 
 
-  static switchProject() {
+  static switchProject(): Promise<void> {
     let token = cookie.get('unscopedToken')
     let token = cookie.get('unscopedToken')
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       if (token) {
       if (token) {
@@ -156,7 +159,7 @@ class UserSource {
     })
     })
   }
   }
 
 
-  static logout() {
+  static logout(): Promise<void> {
     let token = cookie.get('token')
     let token = cookie.get('token')
 
 
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
@@ -178,7 +181,7 @@ class UserSource {
     })
     })
   }
   }
 
 
-  static getUserInfo(user) {
+  static getUserInfo(user: User): Promise<User> {
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       Api.sendAjaxRequest({
       Api.sendAjaxRequest({
         url: `${servicesUrl.users}/${user.id}`,
         url: `${servicesUrl.users}/${user.id}`,

+ 3 - 3
src/stores/ReplicaStore.js

@@ -55,7 +55,7 @@ class ReplicaStore {
   @observable backgroundLoading: boolean = false
   @observable backgroundLoading: boolean = false
   @observable detailsLoading: boolean = true
   @observable detailsLoading: boolean = true
 
 
-  @action getReplicas(options?: { showLoading: boolean }): Promise<MainItem[]> {
+  @action getReplicas(options?: { showLoading: boolean }): Promise<void> {
     this.backgroundLoading = true
     this.backgroundLoading = true
 
 
     if ((options && options.showLoading) || this.replicas.length === 0) {
     if ((options && options.showLoading) || this.replicas.length === 0) {
@@ -72,7 +72,7 @@ class ReplicaStore {
     })
     })
   }
   }
 
 
-  @action getReplicaExecutions(replicaId: string): Promise<Execution[]> {
+  @action getReplicaExecutions(replicaId: string): Promise<void> {
     return ReplicaSource.getReplicaExecutions(replicaId).then(executions => {
     return ReplicaSource.getReplicaExecutions(replicaId).then(executions => {
       let replica = this.replicas.find(replica => replica.id === replicaId)
       let replica = this.replicas.find(replica => replica.id === replicaId)
 
 
@@ -89,7 +89,7 @@ class ReplicaStore {
     })
     })
   }
   }
 
 
-  @action getReplica(replicaId: string): Promise<MainItem> {
+  @action getReplica(replicaId: string): Promise<void> {
     this.detailsLoading = true
     this.detailsLoading = true
 
 
     return ReplicaSource.getReplica(replicaId).then(replica => {
     return ReplicaSource.getReplica(replicaId).then(replica => {

+ 4 - 4
src/stores/UserStore.js

@@ -68,7 +68,7 @@ class UserStore {
     })
     })
   }
   }
 
 
-  @action getUserInfo(user: User): Promise<User> {
+  @action getUserInfo(user: User): Promise<void> {
     return UserSource.getUserInfo(user).then((userData: User) => {
     return UserSource.getUserInfo(user).then((userData: User) => {
       this.user = { ...this.user, ...userData }
       this.user = { ...this.user, ...userData }
     }).catch(reason => {
     }).catch(reason => {
@@ -77,7 +77,7 @@ class UserStore {
     })
     })
   }
   }
 
 
-  @action tokenLogin(): Promise<User> {
+  @action tokenLogin(): Promise<void> {
     this.user = null
     this.user = null
     this.loading = true
     this.loading = true
 
 
@@ -91,10 +91,10 @@ class UserStore {
     })
     })
   }
   }
 
 
-  @action switchProject(projectId: string): Promise<User> {
+  @action switchProject(projectId: string): Promise<void> {
     NotificationStore.notify('Switching projects')
     NotificationStore.notify('Switching projects')
     return UserSource.switchProject().then(() => {
     return UserSource.switchProject().then(() => {
-      return this.loginScoped(projectId)
+      this.loginScoped(projectId)
     }).catch(reason => {
     }).catch(reason => {
       console.error('Error switching projects', reason)
       console.error('Error switching projects', reason)
       NotificationStore.notify('Error switching projects')
       NotificationStore.notify('Error switching projects')

+ 2 - 1
src/types/User.js

@@ -17,10 +17,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import type { Project } from './Project'
 import type { Project } from './Project'
 
 
 export type User = {
 export type User = {
-  scoped: boolean,
+  scoped?: boolean,
   project: Project,
   project: Project,
   email: string,
   email: string,
   name: string,
   name: string,
+  id: string,
 }
 }
 
 
 export type Credentials = {
 export type Credentials = {