]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add notification component
authorTiago Melo <tmelo@suse.com>
Tue, 27 Mar 2018 20:25:15 +0000 (21:25 +0100)
committerTiago Melo <tmelo@suse.com>
Tue, 10 Apr 2018 15:07:27 +0000 (16:07 +0100)
This component is used on the navigation bar and will show the user the 10 most
recent notifications.

Signed-off-by: Tiago Melo <tmelo@suse.com>
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation.module.ts
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/styles/popover.scss [new file with mode: 0644]

index 823d4feea18492767193911210e91d708490288b..6c11b05fd07d0a5bdb358a118b023eeea166dd0b 100644 (file)
@@ -3,22 +3,25 @@ import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
 
 import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
+import { PopoverModule } from 'ngx-bootstrap/popover';
 
 import { AppRoutingModule } from '../../app-routing.module';
 import { SharedModule } from '../../shared/shared.module';
 import { AuthModule } from '../auth/auth.module';
 import { NavigationComponent } from './navigation/navigation.component';
+import { NotificationsComponent } from './notifications/notifications.component';
 
 @NgModule({
   imports: [
     CommonModule,
     AuthModule,
     BsDropdownModule.forRoot(),
+    PopoverModule.forRoot(),
     AppRoutingModule,
     SharedModule,
     RouterModule
   ],
-  declarations: [NavigationComponent],
+  declarations: [NavigationComponent, NotificationsComponent],
   exports: [NavigationComponent]
 })
 export class NavigationModule {}
index cd7e8040c81b7ce5400e23b759acf5724003811a..a00e7cef6fe573dceb5cae13abab0a44a7fbc5f4 100644 (file)
     <!-- /.navbar-primary -->
 
     <ul class="nav navbar-nav navbar-utility">
+      <li>
+        <cd-notifications class="oa-navbar"></cd-notifications>
+      </li>
+
       <li class="tc_logout">
         <cd-logout class="oa-navbar"></cd-logout>
       </li>
index 7548b2bd7c1ff8ed48687464e205835292fe2b20..e2df965f70c4b3c838cb150b9cd9817563face83 100644 (file)
@@ -2,28 +2,34 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { RouterTestingModule } from '@angular/router/testing';
 
+import { PopoverModule } from 'ngx-bootstrap/popover';
+
+import { NotificationService } from '../../../shared/services/notification.service';
 import { SharedModule } from '../../../shared/shared.module';
 import { LogoutComponent } from '../../auth/logout/logout.component';
+import { NotificationsComponent } from '../notifications/notifications.component';
 import { NavigationComponent } from './navigation.component';
 
 describe('NavigationComponent', () => {
   let component: NavigationComponent;
   let fixture: ComponentFixture<NavigationComponent>;
 
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      imports: [
-        SharedModule,
-        RouterTestingModule,
-        HttpClientTestingModule
-      ],
-      declarations: [
-        NavigationComponent,
-        LogoutComponent
-      ]
+  const fakeService = new NotificationService(null);
+
+  beforeEach(
+    async(() => {
+      TestBed.configureTestingModule({
+        imports: [
+          SharedModule,
+          RouterTestingModule,
+          HttpClientTestingModule,
+          PopoverModule.forRoot()
+        ],
+        declarations: [NavigationComponent, NotificationsComponent, LogoutComponent],
+        providers: [{ provide: NotificationService, useValue: fakeService }]
+      }).compileComponents();
     })
-    .compileComponents();
-  }));
+  );
 
   beforeEach(() => {
     fixture = TestBed.createComponent(NavigationComponent);
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.html
new file mode 100644 (file)
index 0000000..db19625
--- /dev/null
@@ -0,0 +1,53 @@
+<ng-template #popTemplate>
+  <div *ngIf="notifications.length > 0">
+    <div class="separator">
+      Recent Notifications
+
+      <div *ngIf="notifications.length > 0"
+           class="pull-right">
+        <a (click)="removeAll()"
+           i18n>Remove all</a>
+      </div>
+    </div>
+    <hr>
+    <div *ngFor="let notification of notifications">
+      <table>
+        <tr>
+          <td rowspan="3" class="icon-col text-center">
+            <span [ngClass]="['fa-stack fa-2x', notification.textClass()]">
+              <i class="fa fa-circle fa-stack-2x"></i>
+              <i [ngClass]="['fa fa-stack-1x fa-inverse', notification.iconClass()]"></i>
+            </span>
+          </td>
+          <td>
+            <strong>{{ notification.title }}</strong>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            {{ notification.message }}
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <small class="date">{{ notification.timestamp | date: 'medium' }}</small>
+          </td>
+        </tr>
+      </table>
+      <hr>
+    </div>
+  </div>
+  <!-- Empty -->
+  <div *ngIf="notifications.length === 0">
+    <div class="message">
+      There are no notifications.
+    </div>
+  </div>
+</ng-template>
+<a [popover]="popTemplate"
+   placement="bottom"
+   container="body"
+   outsideClick="true">
+  <i class="fa fa-bell"></i>
+  <span i18n>Recent Notifications</span>
+</a>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.scss
new file mode 100644 (file)
index 0000000..cf9caf6
--- /dev/null
@@ -0,0 +1,5 @@
+@import '../../../../styles/popover.scss';
+
+.icon-col {
+  width: 70px !important;
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts
new file mode 100644 (file)
index 0000000..b4043fc
--- /dev/null
@@ -0,0 +1,33 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PopoverModule } from 'ngx-bootstrap/popover';
+
+import { NotificationService } from '../../../shared/services/notification.service';
+import { NotificationsComponent } from './notifications.component';
+
+describe('NotificationsComponent', () => {
+  let component: NotificationsComponent;
+  let fixture: ComponentFixture<NotificationsComponent>;
+
+  const fakeService = new NotificationService(null);
+
+  beforeEach(
+    async(() => {
+      TestBed.configureTestingModule({
+        imports: [PopoverModule.forRoot()],
+        declarations: [NotificationsComponent],
+        providers: [{ provide: NotificationService, useValue: fakeService }]
+      }).compileComponents();
+    })
+  );
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NotificationsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.ts
new file mode 100644 (file)
index 0000000..23211c5
--- /dev/null
@@ -0,0 +1,29 @@
+import { Component, OnInit } from '@angular/core';
+
+import { NotificationType } from '../../../shared/enum/notification-type.enum';
+import { CdNotification } from '../../../shared/models/cd-notification';
+import { NotificationService } from '../../../shared/services/notification.service';
+
+@Component({
+  selector: 'cd-notifications',
+  templateUrl: './notifications.component.html',
+  styleUrls: ['./notifications.component.scss']
+})
+export class NotificationsComponent implements OnInit {
+  notifications: CdNotification[];
+  notificationType = NotificationType;
+
+  constructor(private notificationService: NotificationService) {
+    this.notifications = [];
+  }
+
+  ngOnInit() {
+    this.notificationService.data$.subscribe((notifications) => {
+      this.notifications = notifications;
+    });
+  }
+
+  removeAll () {
+    this.notificationService.removeAll();
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/popover.scss b/src/pybind/mgr/dashboard/frontend/src/styles/popover.scss
new file mode 100644 (file)
index 0000000..a2acc01
--- /dev/null
@@ -0,0 +1,44 @@
+::ng-deep .popover-content {
+  padding: 0px 0px;
+  height: auto;
+  max-height: 700px;
+  overflow-x: hidden;
+}
+
+::ng-deep .popover {
+  min-width: 276px !important;
+}
+
+.separator {
+  padding: 5px 12px;
+  color: #90949c;
+  background-color: #f6f7f9;
+  font-size: 12px;
+}
+
+.message {
+  padding: 10px 16px;
+  color: #474544;
+  font-size: 12px;
+}
+
+table {
+  width: 252px;
+  margin: 5px 12px 5px 5px;
+  font-size: 12px;
+  color: #474544;
+}
+
+.icon-col {
+  width: 20px;
+  font-size: 15px;
+}
+
+.date {
+  color: #777777;
+}
+
+hr {
+  margin-top: 0px;
+  margin-bottom: 0px;
+}