airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From machris...@apache.org
Subject [airavata-django-portal] 03/03: AIRAVATA-3071 Converted notices dropdown to Vue
Date Thu, 11 Jul 2019 16:18:55 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 3d6a2cc1cd341a9ed6724a20051880473f940b25
Author: Marcus Christie <machristie@apache.org>
AuthorDate: Thu Jul 11 12:18:42 2019 -0400

    AIRAVATA-3071 Converted notices dropdown to Vue
---
 django_airavata/apps/api/models.py                 |   2 +
 django_airavata/apps/api/serializers.py            |   9 +-
 django_airavata/apps/api/views.py                  |  12 +--
 django_airavata/context_processors.py              |  71 +++++----------
 .../static/common/js/ack-notifications.js          |  28 ------
 .../js/components/GatewayNoticesContainer.vue      | 101 +++++++++++++++++++++
 django_airavata/static/common/js/main.js           |   1 -
 django_airavata/static/common/js/notices.js        |  23 +++++
 django_airavata/static/common/vue.config.js        |   3 +-
 django_airavata/templates/base.html                |  41 +--------
 10 files changed, 168 insertions(+), 123 deletions(-)

diff --git a/django_airavata/apps/api/models.py b/django_airavata/apps/api/models.py
index eb7a725..fd44cca 100644
--- a/django_airavata/apps/api/models.py
+++ b/django_airavata/apps/api/models.py
@@ -10,6 +10,7 @@ class WorkspacePreferences(models.Model):
     def create(self, username):
         return WorkspacePreferences(username=username)
 
+
 class User_Notifications(models.Model):
     class Meta:
         unique_together = (('username', 'notification_id'),)
@@ -18,6 +19,7 @@ class User_Notifications(models.Model):
     notification_id = models.CharField(max_length=255)
     is_read = models.BooleanField(default=False)
 
+
 class User_Files(models.Model):
     username = models.CharField(max_length=64)
     file_path = models.TextField()
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 947b15b..36ea437 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -55,9 +55,9 @@ from airavata.model.job.ttypes import JobModel
 from airavata.model.status.ttypes import ExperimentStatus
 from airavata.model.user.ttypes import UserProfile
 from airavata.model.workspace.ttypes import (
-    Project,
     Notification,
-    NotificationPriority
+    NotificationPriority,
+    Project
 )
 
 from . import data_products_helper, models, thrift_utils
@@ -858,10 +858,12 @@ class IAMUserProfile(serializers.Serializer):
             set(existing_group_ids) - set(new_group_ids))
         return instance
 
+
 class AckNotificationSerializer(serializers.ModelSerializer):
     class Meta:
         model = models.User_Notifications
 
+
 class NotificationSerializer(
         thrift_utils.create_serializer_class(Notification)):
     url = FullyEncodedHyperlinkedIdentityField(
@@ -869,10 +871,11 @@ class NotificationSerializer(
         lookup_field='notificationId',
         lookup_url_kwarg='notification_id')
     priority = thrift_utils.ThriftEnumField(NotificationPriority)
-    creationTime = UTCPosixTimestampDateTimeField(allow_null = True)
+    creationTime = UTCPosixTimestampDateTimeField(allow_null=True)
     publishedTime = UTCPosixTimestampDateTimeField()
     expirationTime = UTCPosixTimestampDateTimeField()
 
+
 class ExperimentStatisticsSerializer(
         thrift_utils.create_serializer_class(ExperimentStatistics)):
     allExperiments = ExperimentSummarySerializer(many=True)
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 5f19b6b..361eaa6 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1399,7 +1399,6 @@ class ManageNotificationViewSet(APIBackedViewSet):
     serializer_class = serializers.NotificationSerializer
     lookup_field = 'notification_id'
 
-
     def get_instance(self, lookup_value):
         return self.request.airavata_client.getNotification(
             self.authz_token, settings.GATEWAY_ID, lookup_value)
@@ -1424,20 +1423,19 @@ class ManageNotificationViewSet(APIBackedViewSet):
 
 class AckNotificationViewSet(APIView):
 
-
     def get(self, request, format=None):
         if 'id' in request.GET:
             notification_id = request.GET['id']
             try:
                 notification = models.User_Notifications.objects.get(
-                                notification_id=notification_id,
-                                username=request.user.username)
+                    notification_id=notification_id,
+                    username=request.user.username)
                 notification.is_read = True
                 notification.save()
             except ObjectDoesNotExist:
-                notification_status = models.User_Notifications.objects.create(
-                            username=request.user.username,
-                            notification_id=notification.notificationId)
+                models.User_Notifications.objects.create(
+                    username=request.user.username,
+                    notification_id=notification.notificationId)
         return HttpResponse(status=204)
 
 
diff --git a/django_airavata/context_processors.py b/django_airavata/context_processors.py
index 63bc225..a70d857 100644
--- a/django_airavata/context_processors.py
+++ b/django_airavata/context_processors.py
@@ -1,81 +1,60 @@
 import copy
-import logging
 import datetime
+import json
+import logging
 import re
 
-from django.urls import reverse
 from django.apps import apps
 from django.conf import settings
-from django_airavata.apps.api.models import User_Notifications
-from django_airavata.app_config import AiravataAppConfig
 from django.core.exceptions import ObjectDoesNotExist
+from django.urls import reverse
 
+from django_airavata.app_config import AiravataAppConfig
+from django_airavata.apps.api.models import User_Notifications
 
 logger = logging.getLogger(__name__)
 
 
-def create_notification_ui(notification):
-    notification.level = {}
-    notification.textColor = "text-info";
-
-    if notification.priority == 0:
-        notification.textColor = "text-primary";
-        notification.level = "badge-info"
-    elif( notification.priority == 1):
-        notification.textColor = "text-warning";
-        notification.level = "badge-warning"
-    elif( notification.priority == 2):
-        notification.textColor = "text-danger";
-        notification.level = "badge-danger"
-
-    if notification.is_read:
-        notification.is_read_text = "read"
-    else:
-        notification.is_read_text = "unread"
-
-    return notification
-
-
 def get_notifications(request):
     if request.user.is_authenticated and hasattr(request, 'airavata_client'):
         unread_notifications = 0
         notifications = request.airavata_client.getAllNotifications(
-                    request.authz_token, settings.GATEWAY_ID)
+            request.authz_token, settings.GATEWAY_ID)
         current_time = datetime.datetime.utcnow()
         valid_notifications = []
         for notification in notifications:
 
-            notification.expirationTime = datetime.datetime.fromtimestamp(
-                                            notification.expirationTime/1000)
-            notification.publishedTime = datetime.datetime.fromtimestamp(
-                                            notification.publishedTime/1000)
+            notification_data = notification.__dict__
+            expirationTime = datetime.datetime.fromtimestamp(
+                notification.expirationTime / 1000)
+            publishedTime = datetime.datetime.fromtimestamp(
+                notification.publishedTime / 1000)
 
-            if(notification.expirationTime > current_time and
-                                    notification.publishedTime < current_time ):
-                notification.url = request.build_absolute_uri( \
-                            reverse('django_airavata_api:ack-notifications'))\
-                            + "?id=" + str(notification.notificationId)
+            if(expirationTime > current_time and publishedTime < current_time):
+                notification_data['url'] = request.build_absolute_uri(
+                    reverse('django_airavata_api:ack-notifications'))\
+                    + "?id=" + str(notification.notificationId)
 
                 try:
                     notification_status = User_Notifications.objects.get(
-                                notification_id=notification.notificationId,
-                                username=request.user.username)
+                        notification_id=notification.notificationId,
+                        username=request.user.username)
                 except ObjectDoesNotExist:
                     notification_status = User_Notifications.objects.create(
-                                username=request.user.username,
-                                notification_id=notification.notificationId)
-                notification.is_read = notification_status.is_read
-                if notification.is_read == False:
+                        username=request.user.username,
+                        notification_id=notification.notificationId)
+                notification_data['is_read'] = notification_status.is_read
+                if not notification_status.is_read:
                     unread_notifications += 1
-                notification = create_notification_ui(notification)
-                valid_notifications.append(notification)
+                valid_notifications.append(notification_data)
 
         return {
-            "notifications": valid_notifications,
+            "notifications": json.dumps(valid_notifications),
             "unread_notifications": unread_notifications
         }
     else:
-        return {"notifications": ""}
+        return {"notifications": json.dumps([])}
+
 
 def airavata_app_registry(request):
     """Put airavata django apps into the context."""
diff --git a/django_airavata/static/common/js/ack-notifications.js b/django_airavata/static/common/js/ack-notifications.js
deleted file mode 100644
index 3d718d1..0000000
--- a/django_airavata/static/common/js/ack-notifications.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import $ from "jquery";
-
-$( "#ack-notification" ).on('click', function(event) {
-
-  if ( event.target.attributes.getNamedItem("notification_id") == null){
-    return;
-  }
-
-  var id = event.target.attributes.getNamedItem("notification_id").value;
-  var url = event.target.attributes.getNamedItem("url").value;
-
-  $.ajax({
-    url: url
-    }).then(function() {
-
-      $("#"+id).prop('hidden','true');
-      var num = parseInt($("#unread_notification_count").attr("data-count")) - 1;
-      //using .attr since the .data method only updates the values in the cache
-      //and they are not reflected on the screen.
-      $("#unread_notification_count").attr("data-count", num);
-
-    });
-  event.stopPropagation();
-});
-
-export default {
-
-};
diff --git a/django_airavata/static/common/js/components/GatewayNoticesContainer.vue b/django_airavata/static/common/js/components/GatewayNoticesContainer.vue
new file mode 100644
index 0000000..8849679
--- /dev/null
+++ b/django_airavata/static/common/js/components/GatewayNoticesContainer.vue
@@ -0,0 +1,101 @@
+<template>
+
+  <div class="btn-group ml-3">
+    <div class=dropdown>
+      <a
+        href=#
+        class="dropdown-toggle text-dark"
+        id=dropdownNoticeButton
+        data-toggle=dropdown
+        title="Notifications"
+        aria-haspopup=true
+        aria-expanded=false
+      >
+        <span
+          class="fa-stack fa-1x has-badge"
+          :data-count="unreadCount"
+          id="unread_notification_count"
+        >
+          <i class="fa fa-circle fa-stack-2x fa-inverse"></i>
+          <i class="fa fa-bell fa-stack-1x"></i>
+        </span>
+      </a>
+      <div
+        class="dropdown-menu widget-notifications no-padding"
+        style="width: 300px"
+      >
+        <div class="notifications-list">
+          <div class="text-center text-primary ">Notifications</div>
+
+          <template v-for="notice in unreadNotices">
+            <div
+              class="dropdown-divider"
+              :key="notice.notificationId"
+            ></div>
+            <div
+              class="dropdown-item"
+              :key="notice.notificationId"
+            >
+              <div>
+                <span
+                  class="notification-title text-wrap"
+                  :class="textColor(notice)"
+                >{{ notice.title }}</span>
+                <a
+                  class="fas fa-dot-circle"
+                  data-toggle="tooltip"
+                  data-placement="left"
+                  title="Mark as read"
+                  :id="notice.notificationId"
+                  @click="ackNotification(notice)"
+                >
+                </a>
+              </div>
+              <div
+                class="notification-description text-wrap"
+                id="notification_description"
+              ><strong>{{ notice.notificationMessage }}</strong></div>
+              <div class="notification-ago time"> {{ fromNow(notice.publishedTime)
}} </div>
+            </div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import moment from "moment";
+import { utils } from "django-airavata-api";
+
+export default {
+  name: "gateway-notices-container",
+  props: ["notices", "unreadCount"],
+  methods: {
+    fromNow(date) {
+      return moment(date).fromNow();
+    },
+    ackNotification(notice) {
+      utils.FetchUtils.get(notice.url).then(() => {
+        notice.is_read = true;
+        this.unreadCount--;
+      });
+    },
+    textColor(notice) {
+      if (notice.priority === 0) {
+        return "text-primary";
+      } else if (notice.priority === 1) {
+        return "text-warning";
+      } else if (notice.priority === 2) {
+        return "text-danger";
+      }
+    }
+  },
+  computed: {
+    unreadNotices() {
+      return this.notices.filter(n => !n.is_read);
+    }
+  }
+};
+</script>
+
diff --git a/django_airavata/static/common/js/main.js b/django_airavata/static/common/js/main.js
index eb22f4d..2c65a38 100644
--- a/django_airavata/static/common/js/main.js
+++ b/django_airavata/static/common/js/main.js
@@ -7,7 +7,6 @@ window.$ = window.jQuery = $;
 import "bootstrap/dist/css/bootstrap.css";
 import "@fortawesome/fontawesome-free/css/all.css";
 import "../scss/main.scss";
-import "./ack-notifications.js";
 $(function() {
   $('[data-toggle="tooltip"]').tooltip();
 });
diff --git a/django_airavata/static/common/js/notices.js b/django_airavata/static/common/js/notices.js
new file mode 100644
index 0000000..3cef9cc
--- /dev/null
+++ b/django_airavata/static/common/js/notices.js
@@ -0,0 +1,23 @@
+import Vue from "vue";
+import GatewayNoticesContainer from "./components/GatewayNoticesContainer";
+
+new Vue({
+  render(h) {
+    return h(GatewayNoticesContainer, {
+      props: {
+        unreadCount: this.unreadCount,
+        notices: this.notices
+      }
+    });
+  },
+  data() {
+    return {
+      unreadCount: null,
+      notices: null
+    };
+  },
+  beforeMount() {
+    this.unreadCount = parseInt(this.$el.dataset.unreadCount);
+    this.notices = JSON.parse(this.$el.dataset.notices);
+  }
+}).$mount("#gateway-notices");
diff --git a/django_airavata/static/common/vue.config.js b/django_airavata/static/common/vue.config.js
index 46c38d9..237b081 100644
--- a/django_airavata/static/common/vue.config.js
+++ b/django_airavata/static/common/vue.config.js
@@ -5,7 +5,8 @@ module.exports = {
   publicPath: "/static/common/dist/",
   pages: {
     app: "./js/main.js",
-    cms: "./js/cms.js"
+    cms: "./js/cms.js",
+    notices: "./js/notices.js"
   },
   configureWebpack: {
     plugins: [
diff --git a/django_airavata/templates/base.html b/django_airavata/templates/base.html
index 60fe313..4fa770f 100644
--- a/django_airavata/templates/base.html
+++ b/django_airavata/templates/base.html
@@ -151,43 +151,7 @@
     </div>
     {% if user.is_authenticated %}
     <div class=c-header__controls>
-      <div class="btn-group ml-3">
-        <div class=dropdown>
-          <a href=# class="dropdown-toggle text-dark" id=dropdownNoticeButton
-            data-toggle=dropdown title="Notifications" aria-haspopup=true
-            aria-expanded=false>
-            <span class="fa-stack fa-1x has-badge" data-count={{ unread_notifications
}} id="unread_notification_count">
-              <i class="fa fa-circle fa-stack-2x fa-inverse"></i>
-              <i class="fa fa-bell fa-stack-1x"></i>
-            </span>
-          </a>
-          <div class="dropdown-menu widget-notifications no-padding" style="width: 300px">
-              <div class="notifications-list" id="ack-notification">
-                <div class="text-center text-primary ">Notifications</div>
-
-                {% for notice in notifications %}
-                  <div class="dropdown-divider"></div>
-                  <div class="dropdown-item">
-                     <div>
-                        <span class="notification-title {{ notice.textColor }} text-wrap">{{
notice.title }}</span>
-                        <a class="fas fa-dot-circle"
-                                data-toggle="tooltip" data-placement="left"
-                                title="Mark as read"
-                                id={{ notice.notificationId }}
-                                notification_id={{ notice.notificationId }}
-                                url={{ notice.url }}
-                                {% if notice.is_read %} hidden {% endif %}
-                                >
-                        </a>
-                      </div>
-                      <div class="notification-description text-wrap" id="notification_description"><strong>{{
notice.notificationMessage }}</strong></div>
-                      <div class="notification-ago time" > {{ notice.publishedTime
| naturaltime }} </div>
-                  </div>
-                {% endfor %}
-              </div>
-          </div>
-        </div>
-      </div>
+      <div id="gateway-notices" data-unread-count="{{ unread_notifications }}" data-notices="{{
notifications }}"></div>
       <div class="btn-group ml-3">
         <div class=dropdown>
           <a href=# class="dropdown-toggle text-dark" id=appDropdownMenuButton data-toggle=dropdown
aria-haspopup=true
@@ -290,6 +254,9 @@
   </script>
   {% render_bundle 'chunk-vendors' 'js' 'COMMON' %}
   {% render_bundle 'app' 'js' 'COMMON' %}
+  {% if user.is_authenticated %}
+    {% render_bundle 'notices' 'js' 'COMMON' %}
+  {% endif %}
   {% block scripts %}
   {% endblock %}
 </body>


Mime
View raw message