airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From machris...@apache.org
Subject [airavata-django-portal] 27/28: AIRAVATA-2876 New and delete deployment
Date Tue, 11 Sep 2018 17:12:15 GMT
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 6b70bc344b6646f52d4fc03441921de183c87131
Author: Marcus Christie <machrist@iu.edu>
AuthorDate: Tue Sep 11 09:51:46 2018 -0400

    AIRAVATA-2876 New and delete deployment
---
 .../src/components/admin/ComputeResourcesModal.vue |  71 +++++
 .../GroupComputeResourcePreference.vue             | 307 ++++++++++-----------
 .../applications/ApplicationDeploymentEditor.vue   |   6 +-
 .../applications/ApplicationDeploymentsList.vue    |  60 ++--
 .../applications/ApplicationEditorContainer.vue    |  74 ++++-
 .../static/django_airavata_admin/src/router.js     |   6 +
 .../src/store/applications/app_deployments.js      |   7 +
 .../src/store/applications/app_modules.js          |   4 +-
 .../api/static/django_airavata_api/js/index.js     |   2 +
 .../js/models/ApplicationDeploymentDescription.js  |   6 +-
 .../django_airavata_api/js/service_config.js       |   3 +-
 django_airavata/apps/api/views.py                  |   4 +
 12 files changed, 355 insertions(+), 195 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/ComputeResourcesModal.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/ComputeResourcesModal.vue
new file mode 100644
index 0000000..460fd26
--- /dev/null
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/ComputeResourcesModal.vue
@@ -0,0 +1,71 @@
+<template>
+  <b-modal title="Select Compute Resource" ref="modal" @ok="onSelectComputeResource" :ok-disabled="modalSelectComputeResourceOkDisabled">
+    <b-form-select v-model="selectedComputeResource" :options="computeResourceOptions">
+      <template slot="first">
+        <option :value="null">Please select compute resource</option>
+      </template>
+    </b-form-select>
+  </b-modal>
+</template>
+
+<script>
+import { models, services } from "django-airavata-api";
+export default {
+  name: "compute-resources-modal",
+  props: {
+    computeResourceNames: Array,
+    excludedResourceIds: Array
+  },
+  data() {
+    return {
+      selectedComputeResource: null,
+      localComputeResourceNames: null
+    };
+  },
+  created() {
+    if (!this.computeResourceNames) {
+      services.ComputeResourceService.namesList().then(
+        resourceNames => (this.localComputeResourceNames = resourceNames)
+      );
+    }
+  },
+  computed: {
+    modalSelectComputeResourceOkDisabled: function() {
+      return this.selectedComputeResource == null;
+    },
+    computeResourceOptions: function() {
+      const names = this.computeResourceNames
+        ? this.computeResourceNames
+        : this.localComputeResourceNames;
+      const options = names
+        ? names
+            .filter(
+              comp =>
+                this.excludedResourceIds
+                  ? !this.excludedResourceIds.includes(comp.host_id)
+                  : true
+            )
+            .map(comp => {
+              return {
+                value: comp.host_id,
+                text: comp.host
+              };
+            })
+        : [];
+      options.sort((a, b) =>
+        a.text.toLowerCase().localeCompare(b.text.toLowerCase())
+      );
+      return options;
+    }
+  },
+  methods: {
+    onSelectComputeResource() {
+      this.$emit("selected", this.selectedComputeResource);
+    },
+    show() {
+      this.$refs.modal.show();
+    }
+  }
+};
+</script>
+
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
index d0f7a98..1cacce5 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
@@ -10,26 +10,20 @@
         <div class="card">
           <div class="card-body">
             <b-form-group label="Name" label-for="profile-name">
-              <b-form-input id="profile-name" type="text"
-                v-model="data.groupResourceProfileName"
-                required placeholder="Name of this Group Resource Profile">
+              <b-form-input id="profile-name" type="text" v-model="data.groupResourceProfileName"
required placeholder="Name of this Group Resource Profile">
               </b-form-input>
             </b-form-group>
-            <share-button ref="shareButton" v-model="sharedEntity"/>
+            <share-button ref="shareButton" v-model="sharedEntity" />
           </div>
         </div>
       </div>
     </div>
-    <list-layout :items="data.computePreferences" title="Compute Preferences"
-      new-item-button-text="New Compute Preference"
-      @add-new-item="createComputePreference">
+    <list-layout :items="data.computePreferences" title="Compute Preferences" new-item-button-text="New
Compute Preference" @add-new-item="createComputePreference">
       <template slot="item-list" slot-scope="slotProps">
 
-        <b-table hover :fields="computePreferencesFields" :items="slotProps.items"
-          sort-by="computeResourceId">
+        <b-table hover :fields="computePreferencesFields" :items="slotProps.items" sort-by="computeResourceId">
           <template slot="policy" slot-scope="row">
-            <compute-resource-policy-summary :compute-resource-id="row.item.computeResourceId"
-              :group-resource-profile="data"/>
+            <compute-resource-policy-summary :compute-resource-id="row.item.computeResourceId"
:group-resource-profile="data" />
           </template>
           <template slot="action" slot-scope="row">
             <router-link :to="{
@@ -51,175 +45,164 @@
               <i class="fa fa-trash" aria-hidden="true"></i>
             </a>
           </template>
-        </b-table> 
+        </b-table>
       </template>
     </list-layout>
     <div class="row">
-        <div class="col d-flex justify-content-end">
-            <b-button variant="primary" @click="saveGroupResourceProfile">Save</b-button>
-            <b-button v-if="id" class="ml-2" variant="danger" @click="removeGroupResourceProfile">Delete</b-button>
-            <b-button class="ml-2" variant="secondary" @click="cancel">Cancel</b-button>
-        </div>
+      <div class="col d-flex justify-content-end">
+        <b-button variant="primary" @click="saveGroupResourceProfile">Save</b-button>
+        <b-button v-if="id" class="ml-2" variant="danger" @click="removeGroupResourceProfile">Delete</b-button>
+        <b-button class="ml-2" variant="secondary" @click="cancel">Cancel</b-button>
+      </div>
     </div>
-    <b-modal id="modal-select-compute-resource" ref="modalSelectComputeResource" title="Select
Compute Resource"
-      @ok="onSelectComputeResource" :ok-disabled="modalSelectComputeResourceOkDisabled">
-      <b-form-select v-model="selectedComputeResource" :options="computeResourceOptions">
-        <template slot="first">
-          <option :value="null">Please select compute resource</option>
-        </template>
-      </b-form-select>
-    </b-modal>
+    <compute-resources-modal ref="modalSelectComputeResource" @selected="onSelectComputeResource"
:excluded-resource-ids="excludedComputeResourceIds"
+    />
   </div>
 </template>
+
 <script>
-  import {components as comps, layouts} from 'django-airavata-common-ui'
-  import {models, services} from 'django-airavata-api'
-  import ComputeResourcePolicySummary from './ComputeResourcePolicySummary.vue'
+import { components as comps, layouts } from "django-airavata-common-ui";
+import { models, services } from "django-airavata-api";
+import ComputeResourcePolicySummary from "./ComputeResourcePolicySummary.vue";
+import ComputeResourcesModal from "../ComputeResourcesModal.vue";
 
-  export default {
-    name: "group-compute-resource-preference",
-    props: {
-      value: {
-        type: models.GroupResourceProfile,
-        default: function () {
-          return new models.GroupResourceProfile()
+export default {
+  name: "group-compute-resource-preference",
+  props: {
+    value: {
+      type: models.GroupResourceProfile,
+      default: function() {
+        return new models.GroupResourceProfile();
+      }
+    },
+    id: {
+      type: String
+    }
+  },
+  mounted: function() {
+    if (this.id) {
+      if (!this.value.groupResourceProfileId) {
+        services.ServiceFactory.service("GroupResourceProfiles")
+          .retrieve({ lookup: this.id })
+          .then(grp => (this.data = grp));
+      }
+      services.ServiceFactory.service("SharedEntities")
+        .retrieve({ lookup: this.id })
+        .then(sharedEntity => (this.sharedEntity = sharedEntity));
+    }
+  },
+  data: function() {
+    let data = this.value.clone();
+    return {
+      data: data,
+      service: services.ServiceFactory.service("GroupResourceProfiles"),
+      sharedEntity: null,
+      computePreferencesFields: [
+        {
+          label: "Name",
+          key: "computeResourceId",
+          sortable: true,
+          formatter: value => this.getComputeResourceName(value)
+        },
+        {
+          label: "Username",
+          key: "loginUserName"
+        },
+        {
+          label: "Allocation",
+          key: "allocationProjectNumber"
+        },
+        {
+          label: "Policy",
+          key: "policy" // custom rendering
+        },
+        {
+          label: "Action",
+          key: "action"
         }
-      },
-      id: {
-        type: String,
-      },
+      ]
+    };
+  },
+
+  components: {
+    "share-button": comps.ShareButton,
+    "list-layout": layouts.ListLayout,
+    ComputeResourcePolicySummary,
+    ComputeResourcesModal
+  },
+  computed: {
+    excludedComputeResourceIds() {
+      const currentPrefs = this.data.computePreferences
+        ? this.data.computePreferences.map(
+            computePreference => computePreference.computeResourceId
+          )
+        : [];
+      return currentPrefs;
     },
-    mounted: function () {
+    title: function() {
+      return this.id
+        ? this.data.groupResourceProfileName
+        : "New Group Resource Profile";
+    }
+  },
+  methods: {
+    saveGroupResourceProfile: function() {
+      var persist = null;
       if (this.id) {
-        if (!this.value.groupResourceProfileId) {
-          services.ServiceFactory.service("GroupResourceProfiles").retrieve({lookup: this.id})
-            .then(grp => this.data = grp);
-        }
-        services.ServiceFactory.service("SharedEntities").retrieve({lookup: this.id})
-          .then(sharedEntity => this.sharedEntity = sharedEntity);
+        persist = this.service.update({ data: this.data, lookup: this.id });
+      } else {
+        persist = this.service.create({ data: this.data }).then(data => {
+          // Save sharing settings too
+          const groupResourceProfileId = data.groupResourceProfileId;
+          return this.$refs.shareButton.mergeAndSave(groupResourceProfileId);
+        });
       }
-      services.ComputeResourceService.namesList()
-        .then(names => this.computeResources = names);
+      persist.then(data => {
+        this.$router.push("/group-resource-profiles");
+      });
     },
-    data: function () {
-      let data = this.value.clone();
-      return {
-        data: data,
-        service: services.ServiceFactory.service("GroupResourceProfiles"),
-        sharedEntity: null,
-        computePreferencesFields: [
-          {
-            label: 'Name',
-            key: 'computeResourceId',
-            sortable: true,
-            formatter: (value) => this.getComputeResourceName(value),
-          },
-          {
-            label: 'Username',
-            key: 'loginUserName'
-          },
-          {
-            label: 'Allocation',
-            key: 'allocationProjectNumber'
-          },
-          {
-            label: 'Policy',
-            key: 'policy', // custom rendering
-          },
-          {
-            label: 'Action',
-            key: 'action',
-          },
-        ],
-        computeResources: null,
-        selectedComputeResource: null,
-      }
+    getComputeResourceName: function(computeResourceId) {
+      // TODO: load compute resources to get the real name
+      return computeResourceId && computeResourceId.indexOf("_") > 0
+        ? computeResourceId.split("_")[0]
+        : computeResourceId;
     },
-
-    components: {
-      "share-button": comps.ShareButton,
-      "list-layout": layouts.ListLayout,
-      ComputeResourcePolicySummary,
+    cancel: function() {
+      this.$router.push("/group-resource-profiles");
     },
-    computed: {
-      modalSelectComputeResourceOkDisabled: function() {
-        return this.selectedComputeResource == null;
-      },
-      computeResourceOptions: function() {
-        const currentPrefs = this.data.computePreferences ? this.data.computePreferences.map(computePreference
=> computePreference.computeResourceId) : [];
-        const options = this.computeResources ? this.computeResources
-          .filter(comp => !currentPrefs.includes(comp.host_id))
-          .map(comp => {
-            return {
-              value: comp.host_id,
-              text: comp.host 
-            }
-          }) : [];
-        options.sort((a, b) => a.text.toLowerCase().localeCompare(b.text.toLowerCase()));
-        return options;
-      },
-      title: function() {
-        return this.id ? this.data.groupResourceProfileName : "New Group Resource Profile";
-      }
+    createComputePreference: function() {
+      this.$refs.modalSelectComputeResource.show();
     },
-    methods: {
-      saveGroupResourceProfile: function () {
-        var persist = null;
-        if (this.id) {
-          persist = this.service.update({data: this.data, lookup: this.id});
-        } else {
-          persist = this.service.create({data: this.data})
-            .then((data) => {
-              // Save sharing settings too
-              const groupResourceProfileId = data.groupResourceProfileId;
-              return this.$refs.shareButton.mergeAndSave(groupResourceProfileId);
-            });
+    onSelectComputeResource: function(computeResourceId) {
+      const computeResourcePreference = new models.GroupComputeResourcePreference();
+      computeResourcePreference.computeResourceId = computeResourceId;
+      this.$router.push({
+        name: "compute_preference_for_new_group_resource_profile",
+        params: {
+          value: computeResourcePreference,
+          id: this.id,
+          host_id: computeResourcePreference.computeResourceId,
+          groupResourceProfile: this.data
         }
-        persist.then(data => {
-          this.$router.push('/group-resource-profiles');
-        });
-      },
-      getComputeResourceName: function (computeResourceId) {
-        // TODO: load compute resources to get the real name
-        return (computeResourceId && computeResourceId.indexOf("_") > 0) ? computeResourceId.split("_")[0]
: computeResourceId;
-      },
-      cancel: function() {
-        this.$router.push('/group-resource-profiles');
-      },
-      createComputePreference: function() {
-        this.$refs.modalSelectComputeResource.show();
-      },
-      onSelectComputeResource: function() {
-        const computeResourcePreference = new models.GroupComputeResourcePreference();
-        const computeResourceId = this.selectedComputeResource;
-        computeResourcePreference.computeResourceId = computeResourceId;
-        this.$router.push({
-          name: 'compute_preference_for_new_group_resource_profile', params: {
-            value: computeResourcePreference,
-            id: this.id,
-            host_id: computeResourcePreference.computeResourceId,
-            groupResourceProfile: this.data,
-          }
+      });
+    },
+    removeComputePreference: function(computeResourceId) {
+      let groupResourceProfile = this.data.clone();
+      groupResourceProfile.removeComputeResource(computeResourceId);
+      this.service
+        .update({ data: groupResourceProfile, lookup: this.id })
+        .then(groupResourceProfile => (this.data = groupResourceProfile));
+    },
+    removeGroupResourceProfile: function() {
+      if (this.id) {
+        this.service.delete({ lookup: this.id }).then(() => {
+          this.$router.push("/group-resource-profiles");
         });
-      },
-      removeComputePreference: function(computeResourceId) {
-
-        let groupResourceProfile = this.data.clone();
-        groupResourceProfile.removeComputeResource(computeResourceId);
-        this.service.update({data: groupResourceProfile, lookup: this.id})
-          .then(groupResourceProfile => this.data = groupResourceProfile);
-      },
-      removeGroupResourceProfile: function() {
-        if (this.id) {
-          this.service.delete({lookup: this.id})
-            .then(() => {
-              this.$router.push('/group-resource-profiles');
-            });
-        } else {
-          // Nothing to delete so just treat like a cancel
-          this.cancel();
-        }
+      } else {
+        // Nothing to delete so just treat like a cancel
+        this.cancel();
       }
-    },
+    }
   }
+};
 </script>
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
index b778577..9bbed4b 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
@@ -52,10 +52,6 @@ export default {
     value: {
       type: models.ApplicationDescriptionDefinition
     },
-    id: {
-      type: String,
-      required: true
-    },
     deployment_id: {
       type: String,
       required: true
@@ -71,7 +67,7 @@ export default {
       if (this.computeResource) {
         return this.computeResource.hostName;
       } else {
-        return this.data.computeHostId.substring(0, 10);
+        return this.data.computeHostId.substring(0, 10) + "...";
       }
     },
     parallelismTypeOptions() {
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
index 05b73e6..5c81732 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
@@ -1,35 +1,41 @@
 <template>
-  <list-layout @add-new-item="newApplicationDeployment" :items="deployments" title="Application
Deployments" new-item-button-text="New Deployment">
-    <template slot="item-list" slot-scope="slotProps">
+  <div>
+    <list-layout @add-new-item="newApplicationDeployment" :items="deployments" title="Application
Deployments" new-item-button-text="New Deployment">
+      <template slot="item-list" slot-scope="slotProps">
 
-      <b-table striped hover :fields="fields" :items="slotProps.items" sort-by="computeHostId">
-        <template slot="action" slot-scope="data">
-          <router-link v-if="!data.item.userHasWriteAccess" :to="{name: 'application_deployment',
params: {id: id, deployment_id: data.item.appDeploymentId}}">
-            View
-            <i class="fa fa-eye" aria-hidden="true"></i>
-          </router-link>
-          <router-link v-if="data.item.userHasWriteAccess" :to="{name: 'application_deployment',
params: {id: id, deployment_id: data.item.appDeploymentId}}">
-            Edit
-            <i class="fa fa-edit" aria-hidden="true"></i>
-          </router-link>
-          <a href="#" class="text-danger" @click.prevent="removeApplicationDeployment(data.item)"
v-if="data.item.userHasWriteAccess">
-            Delete
-            <i class="fa fa-trash" aria-hidden="true"></i>
-          </a>
-        </template>
-      </b-table>
-    </template>
-  </list-layout>
+        <b-table striped hover :fields="fields" :items="slotProps.items" sort-by="computeHostId">
+          <template slot="action" slot-scope="data">
+            <router-link v-if="!data.item.userHasWriteAccess" :to="{name: 'application_deployment',
params: {id: id, deployment_id: data.item.appDeploymentId}}">
+              View
+              <i class="fa fa-eye" aria-hidden="true"></i>
+            </router-link>
+            <router-link v-if="data.item.userHasWriteAccess" :to="{name: 'application_deployment',
params: {id: id, deployment_id: data.item.appDeploymentId}}">
+              Edit
+              <i class="fa fa-edit" aria-hidden="true"></i>
+            </router-link>
+            <a href="#" class="text-danger" @click.prevent="removeApplicationDeployment(data.item)"
v-if="data.item.userHasWriteAccess">
+              Delete
+              <i class="fa fa-trash" aria-hidden="true"></i>
+            </a>
+          </template>
+        </b-table>
+      </template>
+    </list-layout>
+    <compute-resources-modal ref="modalSelectComputeResource" @selected="onSelectComputeResource"
:excluded-resource-ids="excludedComputeResourceIds"
+    />
+  </div>
 </template>
 
 <script>
 import { models, services } from "django-airavata-api";
 import { layouts } from "django-airavata-common-ui";
+import ComputeResourcesModal from "../admin/ComputeResourcesModal.vue";
 
 export default {
   name: "application-deployments-list",
   components: {
-    "list-layout": layouts.ListLayout
+    "list-layout": layouts.ListLayout,
+    ComputeResourcesModal
   },
   props: {
     deployments: {
@@ -65,6 +71,9 @@ export default {
           key: "action"
         }
       ];
+    },
+    excludedComputeResourceIds() {
+      return this.deployments.map(dep => dep.computeHostId);
     }
   },
   mounted() {
@@ -82,6 +91,15 @@ export default {
       } else {
         return computeResourceId.substring(0, 10) + "...";
       }
+    },
+    onSelectComputeResource(computeResourceId) {
+      this.$emit("new", computeResourceId);
+    },
+    newApplicationDeployment() {
+      this.$refs.modalSelectComputeResource.show();
+    },
+    removeApplicationDeployment(deployment) {
+      this.$emit("delete", deployment);
     }
   }
 };
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
index ef371b2..4ca9e7f 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
@@ -17,7 +17,8 @@
         <router-view name="module" v-if="module" v-model="module" @save="saveModule" @cancel="cancelModule"
/>
         <router-view name="interface" v-if="appInterface" v-model="appInterface" @save="saveInterface"
@cancel="cancelInterface"
         />
-        <router-view name="deployments" v-if="deployments" :deployments="deployments"
/>
+        <router-view name="deployments" v-if="deployments" :deployments="deployments"
@new="createNewDeployment" @delete="deleteDeployment"
+        />
         <router-view name="deployment" v-if="deployment" v-model="deployment" @save="saveDeployment"
@cancel="cancelDeployment" />
       </div>
     </div>
@@ -33,7 +34,8 @@ export default {
   name: "application-editor-container",
   props: {
     id: String,
-    deployment_id: String
+    deployment_id: String,
+    hostId: String
   },
   data: function() {
     return {
@@ -63,6 +65,8 @@ export default {
     this.initialize();
     if (this.deployment_id) {
       this.loadApplicationDeployment(this.deployment_id);
+    } else if (this.hostId) {
+      this.createNewDeployment(this.hostId);
     }
   },
   methods: {
@@ -80,7 +84,8 @@ export default {
       "loadApplicationDeployments",
       "loadApplicationDeployment",
       "createApplicationDeployment",
-      "updateApplicationDeployment"
+      "updateApplicationDeployment",
+      "deleteApplicationDeployment"
     ]),
     initialize() {
       // TODO: move this to applications store?
@@ -138,11 +143,74 @@ export default {
         })
         .catch(error => notifications.NotificationList.addError(error));
     },
+    createNewDeployment(computeHostId) {
+      const deployment = new models.ApplicationDeploymentDescription();
+      deployment.appModuleId = this.id;
+      deployment.computeHostId = computeHostId;
+      this.deployment = deployment;
+      this.$router.push({
+        name: "new_application_deployment",
+        params: { id: this.id, hostId: computeHostId }
+      });
+    },
+    saveDeployment() {
+      return this.saveAll().then(appDeployment => {
+        this.$router.push({
+          name: "application_deployments",
+          params: { id: this.id }
+        });
+      });
+    },
+    saveAll() {
+      const moduleSave = this.id
+        ? this.updateApplicationModule(this.module)
+        : this.createApplicationModule(this.module);
+      return moduleSave
+        .then(appModule => {
+          this.appInterface.applicationName = appModule.appModuleName;
+          this.appInterface.applicationDescription =
+            appModule.appModuleDescription;
+
+          if (this.appInterface.applicationInterfaceId) {
+            return this.updateApplicationInterface(this.appInterface);
+          } else {
+            this.appInterface.applicationModules = [this.id];
+            return this.createApplicationInterface(this.appInterface);
+          }
+        })
+        .then(appInterface => {
+          if (this.deployment) {
+            if (this.deployment.appDeploymentId) {
+              return this.updateApplicationDeployment(this.deployment);
+            } else {
+              return this.createApplicationDeployment(this.deployment);
+            }
+          } else {
+            return Promise.resolve(null);
+          }
+        });
+    },
     cancelModule() {
       this.$router.push({ path: "/applications" });
     },
     cancelInterface() {
       this.$router.push({ path: "/applications" });
+    },
+    cancelDeployment() {
+      this.$router.push({
+        name: "application_deployments",
+        params: { id: this.id }
+      });
+    },
+    deleteDeployment(deployment) {
+      return this.deleteApplicationDeployment(deployment)
+        .then(() => this.loadApplicationDeployments(this.id))
+        .then(() => {
+          this.$router.push({
+            name: "application_deployments",
+            params: { id: this.id }
+          });
+        });
     }
   },
   watch: {
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/router.js b/django_airavata/apps/admin/static/django_airavata_admin/src/router.js
index 23d68cc..43583ee 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/router.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/router.js
@@ -75,6 +75,12 @@ const routes = [
         }
       },
       {
+        path: 'deployments/new/:hostId', components: {
+          deployment: ApplicationDeploymentEditor
+        },
+        name: 'new_application_deployment',
+      },
+      {
         path: 'deployments/:deployment_id', components: {
           deployment: ApplicationDeploymentEditor
         },
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_deployments.js
b/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_deployments.js
index c042e8c..65c05f8 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_deployments.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_deployments.js
@@ -42,6 +42,13 @@ export default {
           commit('setCurrentDeployment', appDeployment);
           return appDeployment;
         })
+    },
+    deleteApplicationDeployment({ commit }, appDeployment) {
+      return services.ApplicationDeploymentService.delete({lookup: appDeployment.appDeploymentId
})
+        .then(() => {
+          commit('setCurrentDeployment', null);
+          return null;
+        });
     }
   }
 }
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_modules.js
b/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_modules.js
index 7678c81..7b3f890 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_modules.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/store/applications/app_modules.js
@@ -45,8 +45,8 @@ export default {
             const appModulesCopy = state.modules.slice();
             appModulesCopy.push(appModule);
             commit('setModules', appModulesCopy);
-            return appModule;
           }
+          return appModule;
         });
     },
     updateApplicationModule({ commit, state }, appModule) {
@@ -57,8 +57,8 @@ export default {
             const appModules = state.modules.filter(mod => mod.appModuleId !== appModule.appModuleId)
             appModules.push(appModule);
             commit('setModules', appModules);
-            return appModule;
           }
+          return appModule;
         })
     }
   }
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index 8c9a497..bfb9569 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -2,6 +2,7 @@ import UnhandledError from './errors/UnhandledError'
 import UnhandledErrorDispatcher from './errors/UnhandledErrorDispatcher'
 import UnhandledErrorDisplayList from './errors/UnhandledErrorDisplayList'
 
+import ApplicationDeploymentDescription from './models/ApplicationDeploymentDescription'
 import ApplicationInterfaceDefinition from './models/ApplicationInterfaceDefinition'
 import ApplicationModule from './models/ApplicationModule'
 import BaseModel from './models/BaseModel'
@@ -54,6 +55,7 @@ exports.errors = {
 }
 
 exports.models = {
+  ApplicationDeploymentDescription,
   ApplicationInterfaceDefinition,
   ApplicationModule,
   BaseModel,
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
index 812d540..1f35bfb 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
@@ -49,7 +49,11 @@ const FIELDS = [
   'defaultNodeCount',
   'defaultCPUCount',
   'defaultWalltime',
-  'editableByUser',
+  {
+    name: 'editableByUser',
+    type: 'boolean',
+    default: false,
+  },
   'userHasWriteAccess'
 ];
 
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
index f7b7408..033958a 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
@@ -1,5 +1,6 @@
 import ApplicationDeploymentDescription from './models/ApplicationDeploymentDescription'
 import ApplicationModule from './models/ApplicationModule';
+import ComputeResourceDescription from './models/ComputeResourceDescription'
 import CredentialSummary from './models/CredentialSummary'
 import Group from './models/Group'
 import GroupResourceProfile from './models/GroupResourceProfile'
@@ -105,7 +106,7 @@ export default {
       url: "/api/compute-resources/all_names_list/",
       requestType: 'get',
     }],
-    modelClass: ApplicationDeploymentDescription,
+    modelClass: ComputeResourceDescription,
   },
   "CredentialSummaries": {
     url: "/api/credential-summaries/",
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 3ca84de..bb0b546 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -413,6 +413,10 @@ class ApplicationDeploymentViewSet(APIBackedViewSet):
                                                                  application_deployment.appDeploymentId,
                                                                  application_deployment)
 
+    def perform_destroy(self, instance):
+        self.request.airavata_client.deleteApplicationDeployment(
+            self.authz_token, instance.appDeploymentId)
+
     @detail_route()
     def queues(self, request, app_deployment_id):
         """Return queues for this deployment with defaults overridden by deployment defaults
if they exist"""


Mime
View raw message