You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2018/02/22 22:10:37 UTC

[airavata-django-portal] 01/02: AIRAVATA-2688 Group edit view and refactored Autocomplete

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 0acb40596366838e195d515b4208de6578f9e6fe
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Feb 22 15:47:57 2018 -0500

    AIRAVATA-2688 Group edit view and refactored Autocomplete
---
 .../js/services/GroupService.js                    | 30 +++++-------
 .../js/group-create-entry-point.js                 |  6 +--
 .../js/group-edit-entry-point.js                   | 25 ++++++++++
 .../js/groups_components/Autocomplete.vue          | 57 +++++++++++++---------
 .../js/groups_components/GroupCreateContainer.vue  | 31 ++++++++++++
 .../js/groups_components/GroupEditContainer.vue    | 37 ++++++++++++++
 .../{GroupCreate.vue => GroupEditor.vue}           | 24 +++++----
 .../js/groups_components/GroupsManageContainer.vue |  5 +-
 .../django_airavata_groups/group_edit.html         | 42 ++++------------
 .../django_airavata_groups/groups_create.html      | 32 ++----------
 django_airavata/apps/groups/urls.py                |  2 +-
 django_airavata/apps/groups/views.py               | 41 ++--------------
 django_airavata/apps/groups/webpack.config.js      |  3 +-
 django_airavata/static/common/package-lock.json    | 23 ++++++++-
 14 files changed, 200 insertions(+), 158 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/GroupService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/GroupService.js
index 015cc38..5ca6e9d 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/GroupService.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/GroupService.js
@@ -5,7 +5,7 @@ import FetchUtils from '../utils/FetchUtils'
 
 class GroupService {
 
-    listMemberGroups(data={}) {
+    list(data={}) {
       if (data && data.results) {
           return Promise.resolve(new PaginationIterator(data, Group));
       } else {
@@ -17,30 +17,24 @@ class GroupService {
       }
     }
 
-    listOwnerGroups(data={}) {
-      if (data && data.results) {
-        return Promise.resolve(new PaginationIterator(data, Group));
-      }
-      else {
-        return fetch('/api/groups/', {
-          credentials: 'include'
-        })
-        .then(response => response.json())
-        .then(json => new PaginationIterator(json, Group));
-      }
-    }
-
     create(group) {
         return FetchUtils.post('/api/groups/', JSON.stringify(group))
             .then(result => new Group(result))
     }
 
-    update() {
-        // TODO
+    update(group) {
+        return FetchUtils.put('/api/groups/' + encodeURIComponent(group.id) + '/', JSON.stringify(group))
+            .then(result => new Group(result));
     }
 
-    get() {
-        // TODO
+    get(groupId, data = null) {
+        if (data) {
+            return Promise.resolve(new Group(data));
+        } else {
+            return FetchUtils.get('/api/groups/'
+                    + encodeURIComponent(groupId) + '/')
+                .then(result => new Group(result));
+        }
     }
 }
 
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js b/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js
index ab5a023..96e8767 100644
--- a/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js
@@ -1,6 +1,6 @@
 import Vue from 'vue'
 import BootstrapVue from 'bootstrap-vue'
-import GroupCreate from './groups_components/GroupCreate.vue'
+import GroupCreateContainer from './groups_components/GroupCreateContainer.vue'
 // This is imported globally on the website so no need to include it again in this view
 // import 'bootstrap/dist/css/bootstrap.css'
 import 'bootstrap-vue/dist/bootstrap-vue.css'
@@ -9,8 +9,8 @@ Vue.use(BootstrapVue);
 
 new Vue({
   el: "#create-group",
-  template: '<group-create></group-create>',
+  template: '<group-create-container></group-create-container>',
   components: {
-      GroupCreate
+      GroupCreateContainer
   }
 })
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js b/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js
new file mode 100644
index 0000000..8303e66
--- /dev/null
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js
@@ -0,0 +1,25 @@
+import Vue from 'vue'
+import BootstrapVue from 'bootstrap-vue'
+import GroupEditContainer from './groups_components/GroupEditContainer.vue'
+// This is imported globally on the website so no need to include it again in this view
+// import 'bootstrap/dist/css/bootstrap.css'
+import 'bootstrap-vue/dist/bootstrap-vue.css'
+
+Vue.use(BootstrapVue);
+
+new Vue({
+  el: "#edit-group",
+  template: '<group-edit-container :groupId="groupId"></group-edit-container>',
+  data: {
+      groupId: null,
+  },
+  components: {
+      GroupEditContainer,
+  },
+  beforeMount: function() {
+      if (this.$el.dataset.groupId) {
+          this.groupId = this.$el.dataset.groupId;
+          console.log("groupId", this.groupId);
+      }
+  }
+})
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/Autocomplete.vue b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/Autocomplete.vue
index 9352805..12e57cb 100644
--- a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/Autocomplete.vue
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/Autocomplete.vue
@@ -1,12 +1,12 @@
 <template>
     <div style="position:relative">
-        <span class="selected-cards" style="position:relative" v-for="item in selected" v-bind:key="item.id">
-          <b-button disabled variant="warning">
-             {{ item.name }}&nbsp;&nbsp;<b-badge variant="light"><a href="#" @click="removeClick(item)">x</a></b-badge>
-          </b-button>&nbsp;&nbsp;
+        <span class="selected-cards" style="position:relative">
+          <b-button variant="warning" v-for="item in selected" v-bind:key="item.id" @click="removeClick(item)">
+             {{ item.name }} <b-badge variant="light"><a href="#">x</a></b-badge>
+          </b-button>
         </span>
         <hr>
-        <input class="form-control" type="text" :value="value" placeholder="Type to get suggestions..." @input="updateValue($event.target.value)"
+        <input class="form-control" type="text" :value="searchValue" placeholder="Type to get suggestions..." @input="updateSearchValue($event.target.value)"
           @keydown.enter = 'enter'
           @keydown.down = 'down'
           @keydown.up = 'up'
@@ -25,8 +25,8 @@ export default {
 
   props: {
     value: {
-      type: String,
-      required: true
+      type: Array,
+      required: false
     },
 
     suggestions: {
@@ -39,19 +39,25 @@ export default {
     return {
       open: false,
       current: 0,
-      selected: [],
+      localValue: this.value ? this.value.slice() : [],
+      searchValue: '',
     }
   },
 
   computed: {
     filtered () {
       return this.suggestions.filter((data) => {
-        return data.name.indexOf(this.value) >= 0
+        return data.name.indexOf(this.searchValue) >= 0
       })
     },
+    selected () {
+        return this.suggestions.filter((suggestion) => {
+            return this.localValue.indexOf(suggestion.id) >= 0;
+        });
+    }
   },
   methods: {
-    updateValue (value) {
+    updateSearchValue (value) {
       if (this.open === false) {
         this.open = true
         this.current = 0
@@ -59,16 +65,15 @@ export default {
       if(value===''){
         this.open = false;
       }
-      this.$emit('input', value)
+      this.searchValue = value;
     },
     enter () {
-      // this.$emit('input', this.filtered[this.current].name)
-      this.$emit('input','');
       var index = this.suggestions.indexOf(this.filtered[this.current].name);
-      if(this.selected.indexOf(this.filtered[this.current])==-1){
-        this.selected.push(this.filtered[this.current]);
+      if(this.localValue.indexOf(this.filtered[this.current].id)==-1){
+        this.localValue.push(this.filtered[this.current].id);
       }
-      this.$emit('updateSelected',this.selected);
+      this.$emit('input',this.localValue);
+      this.searchValue = '';
       this.open = false
     },
     up () {
@@ -85,20 +90,24 @@ export default {
       return index === this.current
     },
     suggestionClick (index) {
-      // this.$emit('input', this.filtered[index].name)
-      this.$emit('input','');
-      if(this.selected.indexOf(this.filtered[index])==-1) {
-        this.selected.push(this.filtered[index]);
+      if(this.localValue.indexOf(this.filtered[index].id)==-1) {
+        this.localValue.push(this.filtered[index].id);
       }
-      this.$emit('updateSelected',this.selected);
+      this.$emit('input',this.localValue);
+      this.searchValue = '';
       this.open = false;
     },
     removeClick(data) {
-      var index = this.selected.indexOf(data);
-      this.selected.splice(index,1);
-      this.$emit('updateSelected',this.selected);
+      var index = this.localValue.indexOf(data.id);
+      this.localValue.splice(index,1);
+      this.$emit('input',this.localValue);
     }
   }
 }
 
 </script>
+<style>
+.selected-cards > button + button {
+    margin-left: 10px;
+}
+</style>
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreateContainer.vue b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreateContainer.vue
new file mode 100644
index 0000000..81b1dd9
--- /dev/null
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreateContainer.vue
@@ -0,0 +1,31 @@
+<template>
+    <group-editor :group="newGroup"></group-editor>
+</template>
+
+<script>
+
+import GroupOwnerList from './GroupOwnerList.vue';
+import GroupMemberList from './GroupMemberList.vue';
+import GroupEditor from './GroupEditor.vue';
+
+import { models, services } from 'django-airavata-api'
+import { components as comps } from 'django-airavata-common-ui'
+
+export default {
+    name: 'group-create-container',
+    data () {
+        return {
+            newGroup: new models.Group(),
+        }
+    },
+    components: {
+        GroupEditor,
+    },
+    methods: {
+    },
+    computed: {
+    },
+    beforeMount: function () {
+    },
+}
+</script>
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditContainer.vue b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditContainer.vue
new file mode 100644
index 0000000..19907d9
--- /dev/null
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditContainer.vue
@@ -0,0 +1,37 @@
+<template>
+    <group-editor v-if="group" :group="group"></group-editor>
+</template>
+
+<script>
+
+import GroupEditor from './GroupEditor.vue';
+
+import { models, services } from 'django-airavata-api'
+import { components as comps } from 'django-airavata-common-ui'
+
+export default {
+    name: 'group-edit-container',
+    props: {
+        groupId: {
+            type: String,
+            required: true,
+        }
+    },
+    data () {
+        return {
+            group: null,
+        }
+    },
+    components: {
+        GroupEditor,
+    },
+    methods: {
+    },
+    computed: {
+    },
+    mounted: function () {
+        services.GroupService.get(this.groupId)
+            .then(group => this.group = group);
+    },
+}
+</script>
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreate.vue b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditor.vue
similarity index 79%
rename from django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreate.vue
rename to django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditor.vue
index 90dbadc..ddba0dc 100644
--- a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupCreate.vue
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupEditor.vue
@@ -7,17 +7,17 @@
     <b-form v-if="show">
 
       <b-form-group id="group1" label="Group Name:" label-for="group_name" description="Name should only contain Alpha Characters">
-        <b-form-input id="group_name" type="text" v-model="newGroup.name" required placeholder="Enter group name">
+        <b-form-input id="group_name" type="text" v-model="localGroup.name" required placeholder="Enter group name">
         </b-form-input>
       </b-form-group>
 
       <b-form-group id="group2" label="Description:" label-for="description">
-        <b-form-textarea id="description" type="text" :rows="6" v-model="newGroup.description" required placeholder="Enter description of the group">
+        <b-form-textarea id="description" type="text" :rows="6" v-model="localGroup.description" required placeholder="Enter description of the group">
         </b-form-textarea>
       </b-form-group>
 
       <b-form-group id="group3" label="Add Members:" label-for="members">
-        <autocomplete id="members" :suggestions="suggestions" v-model="selection" v-on:updateSelected="updateSelectedValue"></autocomplete>
+        <autocomplete id="members" :suggestions="suggestions" v-model="localGroup.members"></autocomplete>
       </b-form-group>
 
       <b-button @click="submitForm" variant="primary">Submit</b-button>
@@ -32,10 +32,16 @@ import { models, services } from 'django-airavata-api'
 import Autocomplete from './Autocomplete.vue'
 
 export default {
+    props: {
+        group: {
+            type: models.Group,
+            required: true,
+        },
+    },
     data () {
         return {
             selection: '',
-            newGroup: new models.Group(),
+            localGroup: this.group.clone(),
             show: true,
             selected: [],
             showDismissibleAlert: {'variant':'success', 'message':'no data', 'dismissable':false},
@@ -51,12 +57,10 @@ export default {
             for(var i=0;i<this.selected.length;i++) {
                 temp.push(this.selected[i].id);
             }
-            this.newGroup.members = temp;
-            console.log(JSON.stringify(this.newGroup));
-            services.GroupService.create(this.newGroup)
-            .then(result => {
-                // TODO: redirect to the group view page
-                window.location.assign("/groups/");
+            this.localGroup.members = temp;
+            services.GroupService.create(this.localGroup)
+            .then(group => {
+                this.$emit('saved', result);
             })
             .catch(error => {
                 this.showDismissibleAlert.dismissable = true;
diff --git a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupsManageContainer.vue b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupsManageContainer.vue
index 78a9f70..1d679ca 100755
--- a/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupsManageContainer.vue
+++ b/django_airavata/apps/groups/static/django_airavata_groups/js/groups_components/GroupsManageContainer.vue
@@ -67,10 +67,7 @@ export default {
         },
     },
     beforeMount: function () {
-        services.GroupService.listMemberGroups(this.groupsDataMembers)
-            .then(result => this.groupMembersPaginator = result);
-
-        services.GroupService.listOwnerGroups(this.groupsDataOwners)
+        services.GroupService.list(this.groupsDataOwners)
             .then(result => this.groupOwnersPaginator = result);
     },
 }
diff --git a/django_airavata/apps/groups/templates/django_airavata_groups/group_edit.html b/django_airavata/apps/groups/templates/django_airavata_groups/group_edit.html
index 507a456..c46fcc8 100755
--- a/django_airavata/apps/groups/templates/django_airavata_groups/group_edit.html
+++ b/django_airavata/apps/groups/templates/django_airavata_groups/group_edit.html
@@ -1,38 +1,16 @@
 {% extends 'base.html' %}
 
-{% block content %}
+{% load static %}
 
-<h1 align="center">Edit Group</h1>
-<br>
-{% block body %}
-<div class="container">
-    {% if user.is_authenticated %}
-    <h5>Group Name: {{ group_name }}</h5>
-    <div class="row">
-        <div class="col-lg-6">
-            <h3>Add</h3>
-            <form action="" method="post">
-                {% csrf_token %}
-                {{ add_form.as_p }}
-                <button class="btn btn-primary btn-xs" type="submit" role="button" name="add">Add</button>
-            </form>
-        </div>
-        <div class="col-lg-6">
-            <h3>Remove</h3>
-            <form action="" method="post">
-                {% csrf_token %}
-                {{ remove_form.as_p }}
-                <button class="btn btn-primary btn-xs" type="submit" role="button" name="remove" onclick="return confirm('Are you sure you want to remove the selected members from the group? This action cannot be undone!')">Remove</button>
-            </form>
-        </div>
-    </div>
-    <br>
-    <br>
-    <p align="right"><a class="btn btn-primary btn-xs" href="{% url 'django_airavata_groups:manage' %}" role="button">Back</a></p>
-    {% else %}
-    <p><a class="btn btn-primary btn-lg" href="{% url 'django_airavata_auth:login' %}" role="button">Login »</a></p>
-    {% endif %}
-</div>
+{% block css %}
+{{ block.super }}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_groups/dist/group-edit.css' %}">
 {% endblock %}
 
+{% block content %}
+<div id="edit-group" data-group-id="{{ group_id }}"></div>
 {% endblock content %}
+
+{% block scripts %}
+<script src="{% static 'django_airavata_groups/dist/group-edit.js' %}"></script>
+{% endblock %}
diff --git a/django_airavata/apps/groups/templates/django_airavata_groups/groups_create.html b/django_airavata/apps/groups/templates/django_airavata_groups/groups_create.html
index fc728de..aeaf012 100755
--- a/django_airavata/apps/groups/templates/django_airavata_groups/groups_create.html
+++ b/django_airavata/apps/groups/templates/django_airavata_groups/groups_create.html
@@ -2,6 +2,11 @@
 
 {% load static %}
 
+{% block css %}
+{{ block.super }}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_groups/dist/group-create.css' %}">
+{% endblock %}
+
 {% block content %}
 <div id="create-group"></div>
 {% endblock content %}
@@ -9,30 +14,3 @@
 {% block scripts %}
 <script src="{% static 'django_airavata_groups/dist/group-create.js' %}"></script>
 {% endblock %}
-
-
-<!-- OLD CODE -->
-
-<!--
-<h1 align="center">Create a Group</h1>
-<br>
-{% block body %}
-<div class="container">
-    {% if user.is_authenticated %}
-    <div class="row">
-        <div class="col-md-12">
-            <h3>Enter Group Details</h3>
-            <form action="" method="post">
-                {% csrf_token %}
-                {{ form.as_p }}
-                <button class="btn btn-primary btn-xs" type="submit" role="button">Submit</button>
-            </form>
-        </div>
-    </div>
-    <br>
-    <p align="right"><a class="btn btn-primary btn-xs" href="{% url 'django_airavata_groups:manage' %}" role="button">Back</a></p>
-    {% else %}
-    <p><a class="btn btn-primary btn-lg" href="{% url 'django_airavata_auth:login' %}" role="button">Login »</a></p>
-    {% endif %}
-</div>
-{% endblock %} -->
diff --git a/django_airavata/apps/groups/urls.py b/django_airavata/apps/groups/urls.py
index 7a599d0..e60076b 100755
--- a/django_airavata/apps/groups/urls.py
+++ b/django_airavata/apps/groups/urls.py
@@ -8,7 +8,7 @@ urlpatterns = [
     url(r'^$', views.groups_manage, name="manage"),
     url(r'^create/', views.groups_create, name='create'),
     url(r'^view/', views.view_group, name='view'),
-    url(r'^edit/', views.edit_group, name='edit'),
+    url(r'^edit/(?P<group_id>[^/]+)/$', views.edit_group, name='edit'),
     url(r'^delete/', views.delete_group, name='delete'),
     url(r'^leave/', views.leave_group, name='leave'),
 ]
\ No newline at end of file
diff --git a/django_airavata/apps/groups/views.py b/django_airavata/apps/groups/views.py
index c448618..69ce264 100755
--- a/django_airavata/apps/groups/views.py
+++ b/django_airavata/apps/groups/views.py
@@ -102,48 +102,15 @@ def view_group(request):
         logger.exception("Failed to load the group details")
         return redirect('/groups')
 
-@login_required
-def edit_group(request):
-
-    gateway_id = settings.GATEWAY_ID
-    group_id = request.GET.get('group_id')
-    users = request.POST.getlist('users')
-    members = request.POST.getlist('members')
-
-    try:
-        user_choices = request.sharing_client.getUsers(gateway_id, 0, -1)
-        member_choices = request.sharing_client.getGroupMembersOfTypeUser(gateway_id, group_id, 0, -1)
-        for user in user_choices:
-            for member in member_choices:
-                if user.userId == member.userId:
-                    user_choices.remove(user)
-        if request.method == 'POST':
-            add_form = AddForm(request.POST, user_choices=[(user.userId, user.userId) for user in user_choices])
-            remove_form = RemoveForm(request.POST, user_choices=[(member.userId, member.userId) for member in member_choices])
-            if 'add' in request.POST:
-                if add_form.is_valid():
-                    add = request.sharing_client.addUsersToGroup(gateway_id, users, group_id)
-                    messages.success(request, 'Selected members have been added successfully!')
-                    return redirect('/groups')
-            elif 'remove' in request.POST:
-                if remove_form.is_valid():
-                    remove = request.sharing_client.removeUsersFromGroup(gateway_id, members, group_id)
-                    messages.success(request, 'Selected members have been removed successfully!')
-                    return redirect('/groups')
-
-        else:
-            add_form = AddForm(user_choices=[(user.userId, user.userId) for user in user_choices])
-            remove_form = RemoveForm(user_choices=[(member.userId, member.userId) for member in member_choices])
-            group_details = request.sharing_client.getGroup(gateway_id, group_id)
 
-    except Exception as e:
-        logger.exception("Failed to edit the group")
-        return redirect('/groups')
+@login_required
+def edit_group(request, group_id):
 
     return render(request, 'django_airavata_groups/group_edit.html', {
-        'group_name': group_details.name, 'add_form': add_form, 'remove_form': remove_form
+        'group_id': group_id,
     })
 
+
 @login_required
 def delete_group(request):
 
diff --git a/django_airavata/apps/groups/webpack.config.js b/django_airavata/apps/groups/webpack.config.js
index f3196ff..1f68b37 100755
--- a/django_airavata/apps/groups/webpack.config.js
+++ b/django_airavata/apps/groups/webpack.config.js
@@ -6,6 +6,7 @@ module.exports = {
   entry: {
     'group-list': './static/django_airavata_groups/js/group-listing-entry-point.js',
     'group-create': './static/django_airavata_groups/js/group-create-entry-point.js',
+    'group-edit': './static/django_airavata_groups/js/group-edit-entry-point.js',
   },
   output: {
     path: path.resolve(__dirname, './static/django_airavata_groups/dist/'),
@@ -61,7 +62,7 @@ module.exports = {
   plugins: [
       // Exclude all but the 'en' locale from moment's locales
       new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /^en$/),
-      new ExtractTextPlugin("main.css"),
+      new ExtractTextPlugin("[name].css"),
   ]
 }
 
diff --git a/django_airavata/static/common/package-lock.json b/django_airavata/static/common/package-lock.json
index 1f00f23..10905ae 100644
--- a/django_airavata/static/common/package-lock.json
+++ b/django_airavata/static/common/package-lock.json
@@ -1927,7 +1927,28 @@
       }
     },
     "django-airavata-api": {
-      "version": "file:../../apps/api"
+      "version": "file:../../apps/api",
+      "requires": {
+        "url-parse": "1.2.0"
+      },
+      "dependencies": {
+        "querystringify": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "requires-port": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "url-parse": {
+          "version": "1.2.0",
+          "bundled": true,
+          "requires": {
+            "querystringify": "1.0.0",
+            "requires-port": "1.0.0"
+          }
+        }
+      }
     },
     "dns-equal": {
       "version": "1.0.0",

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.