Merge branch '17-Yuyu-Features/dashboard-notification' into 'main'

Dashboard Notification Center

Closes #17

See merge request dev/yuyu_dashboard!9
This commit is contained in:
Setyo Nugroho 2022-07-20 09:21:19 +00:00
commit e70423ce86
11 changed files with 303 additions and 1 deletions

View file

@ -13,6 +13,7 @@ ln -sf $root/yuyu/local/enabled/_6103_admin_billing_price_configuration.py $hori
ln -sf $root/yuyu/local/enabled/_6104_admin_billing_setting.py $horizon_path/openstack_dashboard/local/enabled/_6104_admin_billing_setting.py
ln -sf $root/yuyu/local/enabled/_6104_admin_billing_setting.py $horizon_path/openstack_dashboard/local/enabled/_6104_admin_billing_setting.py
ln -sf $root/yuyu/local/enabled/_6105_admin_billing_projects_invoice.py $horizon_path/openstack_dashboard/local/enabled/_6105_admin_billing_projects_invoice.py
ln -sf $root/yuyu/local/enabled/_6106_admin_notification_center.py $horizon_path/openstack_dashboard/local/enabled/_6105_admin_notification_center.py
ln -sf $root/yuyu/local/enabled/_6111_project_billing_panel_group.py $horizon_path/openstack_dashboard/local/enabled/_6111_project_billing_panel_group.py
ln -sf $root/yuyu/local/enabled/_6112_project_billing_overview.py $horizon_path/openstack_dashboard/local/enabled/_6112_project_billing_overview.py

View file

@ -0,0 +1,20 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.utils.translation import ugettext_lazy as _
import horizon
class NotificationCenter(horizon.Panel):
name = _("Notification Center")
slug = "notification_center"

View file

@ -0,0 +1,27 @@
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import tables
class NotificationFilterAction(tables.FilterAction):
name = "notification_center_filter"
class NotificationTable(tables.DataTable):
title = tables.WrappingColumn("title", verbose_name=_("Title"),
link="horizon:admin:notification_center:detail")
short_description = tables.Column("short_description", verbose_name=_("Short Description"))
recipient = tables.Column("recipient", verbose_name=_("Recipient"))
sent_status = tables.Column("sent_status", verbose_name=_("Sent Status"))
is_read = tables.Column("is_read", verbose_name=_("Is Read"))
created_at = tables.Column("created_at", verbose_name=_("Created At"))
def get_object_id(self, obj):
return obj["id"]
class Meta(object):
name = "list_notification_center"
verbose_name = _("Notification Center")
multi_select = False
table_actions = (NotificationFilterAction, )

View file

@ -0,0 +1,60 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Notification Center" %}{% endblock %}
{% block main %}
<div class="row">
<div class="col-sm-6">
<dl class="dl-horizontal">
<dt>Project: </dt>
<dd>
<select id="selection" onchange="onSelection(this.value)">
<option value='{}'
{% if not current_tenant_id %}selected {% endif %}
>All</option>
<option
value='{"tenant_id": "0"}'
{% if "0" == current_tenant_id %}selected {% endif %}
>General Notification
</option>
{% for i in select_list %}
<option
value='{"tenant_id": "{{ i.id }}"}'
{% if i.id == current_tenant_id %}selected {% endif %}
>{{ i.name }}
</option>
{% endfor %}
</select>
</dd>
</dl>
</div>
<div class="col-sm-6 text-right">
<a href="{% url 'horizon:admin:notification_center:read_all' current_tenant_id %}"
class="btn btn-primary" style="margin-bottom: 8px">Mark to Read All</a>
</div>
</div>
<div class="row">
<div class="col-sm-12">
{{ table.render }}
</div>
</div>
{% endblock %}
{% block js %}
{{ block.super }}
<script type="text/javascript">
function onSelection(val) {
const data = JSON.parse(val);
if(data !== null){
var search = "?tenant_id=" + data.tenant_id;
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname + search;
}else {
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname;
}
}
</script>
{% endblock %}

View file

@ -0,0 +1,49 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Detail Notification" %}{% endblock %}
{% block main %}
<div class="row">
<div class="col-sm-12 text-right">
{% if not notification.sent_status %}
<a href="{% url 'horizon:admin:notification_center:resend' notification.id%}"
class="btn btn-primary" style="margin-bottom: 8px">Resend Notification</a>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading"><strong>{{ notification.title }}/{{ notification.id }}</strong></div>
<div class="panel-body">
<span><strong>Description:</strong></span>
<p>{{ notification.short_description }}</p>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">Recipient</th>
<th scope="col">Sent Status</th>
<th scope="col">Is Read</th>
<th scope="col">Created At</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ notification.project.email_notification }}</td>
<td>{{ notification.sent_status }}</td>
<td>{{ notification.is_read }}</td>
<td>{{ notification.created_at }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
{% autoescape off %}{{ notification.content }}{% endautoescape %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,27 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<notification_id>[^/]+)/$',
views.DetailView.as_view(),
name='detail'),
url(r'^resend/(?P<notification_id>[^/]+)/$',
views.ResendView.as_view(),
name='resend'),
url(r'^read_all/(?P<selection>[^/]+)$', views.ReadAllView.as_view(), name='read_all'),
]

View file

@ -0,0 +1,90 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django import shortcuts
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions, tables, views
from openstack_dashboard import api
from .tables import NotificationTable
from ...cases.notification_use_case import NotificationCenterUseCase
class IndexView(tables.DataTableView):
page_title = _("Notification Center")
template_name = "admin/notification_center/index.html"
table_class = NotificationTable
notification_uc = NotificationCenterUseCase()
def get_data(self):
filter_selection = self.request.GET.get('tenant_id', None)
try:
notification_uc = self.notification_uc.get_list(self.request, filter_selection)
except Exception:
notification_uc = []
exceptions.handle(self.request,
_("Unable to retrieve data."))
return notification_uc
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if hasattr(self, "table"):
context[self.context_object_name] = self.table
context['select_list'], _ = api.keystone.tenant_list(self.request, user=self.request.user.id)
context['current_tenant_id'] = self.request.GET.get('tenant_id', None)
return context
class DetailView(views.APIView):
page_title = _("Notification Detail")
template_name = "admin/notification_center/notification_detail.html"
notification_uc = NotificationCenterUseCase()
def get_data(self, request, context, *args, **kwargs):
context = super().get_context_data(**kwargs)
notification_uc = self.notification_uc.get_detail(self.request,
notification_id=self.kwargs['notification_id'])
context['notification'] = notification_uc
return context
class ReadAllView(views.APIView):
notification_uc = NotificationCenterUseCase()
def get(self, request, *args, **kwargs):
try:
notifications = self.notification_uc.get_list(self.request,
filter_selection=self.kwargs['selection'])
for n in notifications:
if not n["is_read"]:
self.notification_uc.set_read(request, n['id'])
except Exception:
exceptions.handle(self.request,
_("Unable to mark read All Notification, Please contact admin"))
return shortcuts.redirect("horizon:admin:notification_center:index")
class ResendView(views.APIView):
notification_uc = NotificationCenterUseCase()
def get(self, request, *args, **kwargs):
try:
notification_id = self.kwargs['notification_id']
self.notification_uc.set_resend(request, notification_id)
except Exception:
exceptions.handle(self.request,
_("Unable to Resend Notification, Please contact admin"))
return shortcuts.redirect("horizon:admin:notification_center:index")

View file

@ -44,7 +44,6 @@ class IndexView(tables.DataTableView):
context['project_list'], _ = api.keystone.tenant_list(self.request, user=self.request.user.id)
context['current_project_id'] = self.request.GET.get('project_id', self.request.user.project_id)
context['current_project_name'] = self.request.GET.get('project_name', self.request.user.project_id)
print(context['project_list'])
return context
def get_data(self):

View file

@ -0,0 +1,20 @@
from openstack_dashboard.dashboards.yuyu.core import yuyu_client
class NotificationCenterUseCase:
def get_list(self, request, filter_selection=None):
if filter_selection is None:
return yuyu_client.get(request, f"notification/").json()
return yuyu_client.get(request, f"notification/?tenant_id={filter_selection}").json()
def get_detail(self, request, notification_id):
response = yuyu_client.get(request, f"notification/{notification_id}").json()
return response
def set_read(self, request, notification_id=None):
return yuyu_client.get(request, f"notification/{notification_id}/set_read/").json()
def set_resend(self, request, notification_id):
return yuyu_client.get(request, f"notification/{notification_id}/resend/").json()

View file

@ -0,0 +1,9 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'notification_center'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'billing'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu.admin.notification_center.panel.NotificationCenter'