Remove the external package and add custom scrollbar.
Fix random e2e tests.
Fixes: https://tracker.ceph.com/issues/43804
Fixes: https://tracker.ceph.com/issues/43593
Signed-off-by: Tiago Melo <tmelo@suse.com>
return $$('legend');
}
+ getToast() {
+ return $('.ngx-toastr');
+ }
+
async waitPresence(elem: ElementFinder, message?: string) {
return browser.wait(EC.presenceOf(elem), TIMEOUT, message);
}
});
afterEach(async () => {
- NotificationSidebarPageHelper.checkConsole();
-
- if (await notification.getCloseBtn().isPresent()) {
- await notification.waitClickableAndClick(notification.getCloseBtn());
- await notification.waitStaleness(notification.getSidebar());
- }
+ await NotificationSidebarPageHelper.checkConsole();
});
it('should open notification sidebar', async () => {
- await notification.waitStaleness(notification.getSidebar());
+ await notification.waitInvisibility(notification.getSidebar());
await notification.open();
await notification.waitVisibility(notification.getSidebar());
});
await pools.navigateTo('create');
await pools.create(poolName, 16);
await pools.edit_pool_pg(poolName, 8, false);
+ await notification.waitStaleness(notification.getToast());
await notification.open();
await notification.waitVisibility(notification.getTasks().first());
});
it('should clear notifications', async () => {
- await notification.open();
+ await notification.waitStaleness(notification.getToast());
await expect((await notification.getNotifications()).length).toBeGreaterThan(0);
+ await notification.waitVisibility(notification.getClearNotficationsBtn());
await notification.waitClickableAndClick(notification.getClearNotficationsBtn());
await notification.waitStaleness(notification.getNotifications().first());
await expect((await notification.getNotifications()).length).toBe(0);
}
getSidebar() {
- return element(by.css('aside.ng-sidebar--opened cd-notifications-sidebar'));
+ return element(by.css('cd-notifications-sidebar'));
}
getTasks() {
"worker-plugin": "3.2.0"
},
"dependencies": {
+ "caniuse-lite": {
+ "version": "1.0.30001019",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz",
+ "integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==",
+ "dev": true
+ },
"core-js": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz",
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"os-locale": {
"version": "3.1.0",
}
},
"mem": {
- "dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"os-locale": {
"version": "3.1.0",
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
- "dev": true,
"requires": {
"p-defer": "^1.0.0"
}
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
- "mem": {
- "requires": {
- "mimic-fn": "^1.0.0"
- },
- "version": "4.3.0"
- },
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
"mime-db": "1.43.0"
}
},
- "mimic-fn": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
- "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
- },
"mini-css-extract-plugin": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz",
"tslib": "^1.9.0"
}
},
- "ng-sidebar": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/ng-sidebar/-/ng-sidebar-9.1.1.tgz",
- "integrity": "sha512-G8BAaV/TsfkMHyy4FbaDEjrKdu0b55aEjZM1Nrz1xG62J/jyfhgK+S0ma3nszUWK6hKMqwXXVBghoX8pl9SoVg=="
+ "ng-click-outside": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ng-click-outside/-/ng-click-outside-5.3.0.tgz",
+ "integrity": "sha512-+WYtu2hSQy0F6VlHOqKhPtdVJimTiXXNtZPBGfLORJNX71ieYGsentke8KG+8EudR36FUB6Ya9g2GwGXM0UqdA=="
},
"ng2-charts": {
"version": "2.3.0",
"dependencies": {
"mem": {
"version": "4.3.0"
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
}
}
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
- "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
- "dev": true
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
},
"p-each-series": {
"version": "1.0.0",
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
- "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
- "dev": true
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
},
"p-limit": {
"version": "1.3.0",
}
},
"mem": {
- "dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"os-locale": {
"version": "3.1.0",
"moment": "2.24.0",
"ng-block-ui": "2.1.7",
"ng-bootstrap-form-validation": "5.0.0",
- "ng-sidebar": "9.1.1",
+ "ng-click-outside": "5.3.0",
"ng2-charts": "2.3.0",
"ng2-tree": "2.0.0-rc.11",
"ngx-bootstrap": "5.1.2",
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
-import { ToastrModule } from 'ngx-toastr';
-
-import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
-import { NotificationService } from '../../../shared/services/notification.service';
+import { configureTestBed } from '../../../../testing/unit-test-helper';
import { AuthModule } from '../auth.module';
import { LoginComponent } from './login.component';
let fixture: ComponentFixture<LoginComponent>;
configureTestBed({
- imports: [RouterTestingModule, HttpClientTestingModule, AuthModule, ToastrModule.forRoot()],
- providers: [i18nProviders]
+ imports: [RouterTestingModule, HttpClientTestingModule, AuthModule]
});
beforeEach(() => {
component.ngOnInit();
expect(component['bsModalService'].getModalsCount()).toBe(0);
});
-
- it('should call toggleSidebar if not logged in', () => {
- const notificationService: NotificationService = TestBed.get(NotificationService);
- spyOn(notificationService, 'toggleSidebar').and.callThrough();
-
- component.ngOnInit();
-
- expect(notificationService.toggleSidebar).toHaveBeenCalledWith(true);
- });
});
import { AuthService } from '../../../shared/api/auth.service';
import { Credentials } from '../../../shared/models/credentials';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
-import { NotificationService } from '../../../shared/services/notification.service';
@Component({
selector: 'cd-login',
private authService: AuthService,
private authStorageService: AuthStorageService,
private bsModalService: BsModalService,
- private router: Router,
- private notificationService: NotificationService
+ private router: Router
) {}
ngOnInit() {
this.bsModalService.hide(i);
}
- // Make sure notification sidebar is closed.
- this.notificationService.toggleSidebar(true);
-
let token: string = null;
if (window.location.hash.indexOf('access_token=') !== -1) {
token = window.location.hash.split('access_token=')[1];
import { RouterModule } from '@angular/router';
import { BlockUIModule } from 'ng-block-ui';
-import { SidebarModule } from 'ng-sidebar';
import { SharedModule } from '../shared/shared.module';
import { ForbiddenComponent } from './forbidden/forbidden.component';
import { NotFoundComponent } from './not-found/not-found.component';
@NgModule({
- imports: [
- BlockUIModule.forRoot(),
- CommonModule,
- NavigationModule,
- RouterModule,
- SharedModule,
- SidebarModule.forRoot()
- ],
+ imports: [BlockUIModule.forRoot(), CommonModule, NavigationModule, RouterModule, SharedModule],
exports: [NavigationModule],
declarations: [
NotFoundComponent,
-<!-- Container for sidebar(s) + page content -->
-<ng-sidebar-container>
- <!-- A sidebar -->
- <ng-sidebar #sidebar
- [(opened)]="sidebarOpened"
- [animate]="sidebarAnimate"
- position="end"
- mode="over"
- autoFocus="false"
- closeOnClickOutside="true">
- <cd-notifications-sidebar></cd-notifications-sidebar>
- </ng-sidebar>
-
- <!-- Page content -->
- <div ng-sidebar-content>
- <block-ui>
- <cd-navigation>
- <div class="container-fluid"
- [ngClass]="{'dashboard':isDashboardPage()} ">
- <cd-breadcrumbs></cd-breadcrumbs>
- <router-outlet></router-outlet>
- </div>
- </cd-navigation>
- </block-ui>
- </div>
-</ng-sidebar-container>
+<block-ui>
+ <cd-navigation>
+ <div class="container-fluid h-100"
+ [ngClass]="{'dashboard':isDashboardPage()} ">
+ <cd-breadcrumbs></cd-breadcrumbs>
+ <router-outlet></router-outlet>
+ </div>
+ </cd-navigation>
+</block-ui>
padding: 0;
}
+.container-fluid {
+ overflow: auto;
+}
+
::ng-deep #toast-container {
margin-top: 2vw;
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
-import { SidebarModule } from 'ng-sidebar';
import { ToastrModule } from 'ngx-toastr';
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
import { RbdService } from '../../../shared/api/rbd.service';
import { PipesModule } from '../../../shared/pipes/pipes.module';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
-import { NotificationService } from '../../../shared/services/notification.service';
import { WorkbenchLayoutComponent } from './workbench-layout.component';
describe('WorkbenchLayoutComponent', () => {
let fixture: ComponentFixture<WorkbenchLayoutComponent>;
configureTestBed({
- imports: [
- RouterTestingModule,
- ToastrModule.forRoot(),
- PipesModule,
- HttpClientTestingModule,
- SidebarModule.forRoot()
- ],
+ imports: [RouterTestingModule, ToastrModule.forRoot(), PipesModule, HttpClientTestingModule],
declarations: [WorkbenchLayoutComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [AuthStorageService, i18nProviders, RbdService]
it('should create', () => {
expect(component).toBeTruthy();
});
-
- describe('Sidebar', () => {
- let notificationService: NotificationService;
-
- beforeEach(() => {
- notificationService = TestBed.get(NotificationService);
- });
-
- it('should always close if sidebarSubject value is true', () => {
- // Closed before next value
- expect(component.sidebarOpened).toBeFalsy();
- notificationService.sidebarSubject.next(true);
- expect(component.sidebarOpened).toBeFalsy();
-
- // Opened before next value
- component.sidebarOpened = true;
- expect(component.sidebarOpened).toBeTruthy();
- notificationService.sidebarSubject.next(true);
- expect(component.sidebarOpened).toBeFalsy();
- });
-
- it('should toggle sidebar visibility if sidebarSubject value is false', () => {
- // Closed before next value
- expect(component.sidebarOpened).toBeFalsy();
- notificationService.sidebarSubject.next(false);
- expect(component.sidebarOpened).toBeTruthy();
-
- // Opened before next value
- component.sidebarOpened = true;
- expect(component.sidebarOpened).toBeTruthy();
- notificationService.sidebarSubject.next(false);
- expect(component.sidebarOpened).toBeFalsy();
- });
- });
});
-import { Component, OnDestroy, ViewChild } from '@angular/core';
+import { Component } from '@angular/core';
import { Router } from '@angular/router';
-import { Sidebar } from 'ng-sidebar';
import { TooltipConfig } from 'ngx-bootstrap/tooltip';
-import { Subscription } from 'rxjs';
import { NotificationService } from '../../../shared/services/notification.service';
}
]
})
-export class WorkbenchLayoutComponent implements OnDestroy {
- @ViewChild(Sidebar, { static: true })
- sidebar: Sidebar;
-
- sidebarOpened = false;
- // There is a bug in ng-sidebar that will show the sidebar closing animation
- // when the page is first loaded. This prevents that.
- sidebarAnimate = false;
-
- private readonly sidebarSubscription: Subscription;
-
- constructor(private router: Router, public notificationService: NotificationService) {
- this.sidebarSubscription = this.notificationService.sidebarSubject.subscribe((forcedClose) => {
- if (forcedClose) {
- this.sidebar.close();
- } else {
- this.sidebarAnimate = true;
- this.sidebarOpened = !this.sidebarOpened;
- }
- });
- }
-
- ngOnDestroy() {
- if (this.sidebarSubscription) {
- this.sidebarSubscription.unsubscribe();
- }
- }
+export class WorkbenchLayoutComponent {
+ constructor(private router: Router, public notificationService: NotificationService) {}
isDashboardPage() {
return this.router.url === '/dashboard';
<cd-pwd-expiration-notification></cd-pwd-expiration-notification>
+<cd-notifications-sidebar></cd-notifications-sidebar>
+
<div class="cd-navbar-top">
- <nav class="navbar fixed-top navbar-expand-md navbar-dark cd-navbar-brand"
- [ngClass]="{'isPwdDisplayed': isPwdDisplayed}">
+ <nav class="navbar fixed-top navbar-expand-md navbar-dark cd-navbar-brand">
<button class="btn btn-link py-0"
(click)="showMenuSidebar = !showMenuSidebar">
<i class="fa fa-bars fa-2x"
<div class="wrapper">
<!-- Content -->
<nav id="sidebar"
- [ngClass]="{'active': !showMenuSidebar, 'isPwdDisplayed': isPwdDisplayed}">
+ [ngClass]="{'active': !showMenuSidebar}">
<ngx-simplebar [options]="simplebar">
<ul class="list-unstyled components cd-navbar-primary">
<ng-container *ngTemplateOutlet="cd_menu"> </ng-container>
<!-- Page Content -->
<div id="content"
- [ngClass]="{'active': !showMenuSidebar, 'isPwdDisplayed': isPwdDisplayed}">
+ [ngClass]="{'active': !showMenuSidebar}">
<ng-content></ng-content>
</div>
</div>
@import 'defaults';
-$pwd-exp-height: 37.6px;
-
/* ---------------------------------------------------
NAVBAR STYLE
--------------------------------------------------- */
--------------------------------------------------- */
$sidebar-width: 200px;
-$navbar-height: 43px;
.cd-navbar-primary .active > a,
.cd-navbar-primary > .active > a:focus,
margin-left: -$sidebar-width;
}
- &.isPwdDisplayed {
- top: $navbar-height + $pwd-exp-height;
- }
-
ul {
&.component {
padding: 20px 0;
top: $navbar-height;
bottom: 0;
right: 0;
- overflow: auto;
&.active {
width: 100vw;
}
+}
- &.isPwdDisplayed {
+/* ---------------------------------------------------
+ isPwdDisplayed
+--------------------------------------------------- */
+:host.isPwdDisplayed {
+ .cd-navbar-top .cd-navbar-brand {
+ top: $pwd-exp-height;
+ }
+
+ #sidebar {
top: $navbar-height + $pwd-exp-height;
}
+
+ #content {
+ top: $navbar-height + $pwd-exp-height;
+ }
+
+ cd-notifications-sidebar {
+ top: $navbar-height + $pwd-exp-height + 10px;
+ }
}
-import { Component, OnInit } from '@angular/core';
+import { Component, HostBinding, OnInit } from '@angular/core';
import { PrometheusService } from '../../../shared/api/prometheus.service';
import { Icons } from '../../../shared/enum/icons.enum';
styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent implements OnInit {
+ @HostBinding('class.isPwdDisplayed') isPwdDisplayed = false;
+
permissions: Permissions;
summaryData: any;
icons = Icons;
isCollapsed = true;
showMenuSidebar = true;
displayedSubMenu = '';
- isPwdDisplayed = false;
simplebar = {
autoHide: false
import { RouterModule } from '@angular/router';
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
+import { ClickOutsideModule } from 'ng-click-outside';
import { ChartsModule } from 'ng2-charts';
import { AlertModule } from 'ngx-bootstrap/alert';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
+import { SimplebarAngularModule } from 'simplebar-angular';
import { DirectivesModule } from '../directives/directives.module';
import { PipesModule } from '../pipes/pipes.module';
DirectivesModule,
BsDropdownModule,
NgBootstrapFormValidationModule,
+ ClickOutsideModule,
+ SimplebarAngularModule,
RouterModule
],
declarations: [
</div>
</ng-template>
-<div class="card">
+<div class="card"
+ (clickOutside)="closeSidebar()"
+ [clickOutsideEnabled]="isSidebarOpened">
<div class="card-header">
<ng-container i18n>Tasks and Notifications</ng-container>
</button>
</div>
- <div class="card-body">
- <ng-container *ngTemplateOutlet="tasksTpl"></ng-container>
- <ng-container *ngTemplateOutlet="notificationsTpl"></ng-container>
- <ng-container *ngTemplateOutlet="emptyTpl"></ng-container>
- </div>
+ <ngx-simplebar [options]="simplebar">
+ <div class="card-body">
+ <ng-container *ngTemplateOutlet="tasksTpl"></ng-container>
+ <ng-container *ngTemplateOutlet="notificationsTpl"></ng-container>
+ <ng-container *ngTemplateOutlet="emptyTpl"></ng-container>
+ </div>
+ </ngx-simplebar>
</div>
@import 'defaults';
-::ng-deep .ng-sidebar__content {
- overflow: hidden !important;
-}
-
-::ng-deep .isPwdDisplayed .ng-sidebar {
- top: 92px !important;
-}
-
-// sidebar
-::ng-deep .ng-sidebar {
- &.ng-sidebar--opened {
- margin-right: 20px;
- }
+:host {
+ position: fixed;
+ top: $navbar-height + 10px;
+ bottom: 10px;
+ right: -350px;
width: 350px;
max-width: 90vw;
- z-index: 9 !important;
- top: 54px !important;
- bottom: 10px !important;
+ z-index: 9;
- .card {
- height: 100%;
+ transition: all 0.6s;
+}
- .card-body {
- overflow: auto;
- }
- }
+:host.active {
+ right: 20px;
+}
- .separator {
- padding: 5px 12px;
- color: $color-popover-seperator-text;
- background-color: $color-popover-seperator-bg;
- font-size: 12px;
- }
+.card {
+ height: 100%;
+}
+
+ngx-simplebar {
+ height: calc(100% - 42.2px);
+}
+
+.separator {
+ padding: 5px 12px;
+ color: $color-popover-seperator-text;
+ background-color: $color-popover-seperator-bg;
+ font-size: 12px;
+}
- .btn-link .fa-trash-o {
- color: $color-black;
- }
+.btn-link .fa-trash-o {
+ color: $color-black;
}
table {
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
+import { ClickOutsideModule } from 'ng-click-outside';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
import { ToastrModule } from 'ngx-toastr';
+import { SimplebarAngularModule } from 'simplebar-angular';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
ProgressbarModule.forRoot(),
RouterTestingModule,
ToastrModule.forRoot(),
- NoopAnimationsModule
+ NoopAnimationsModule,
+ SimplebarAngularModule,
+ ClickOutsideModule
],
declarations: [NotificationsSidebarComponent],
providers: [
expectPrometheusServicesToBeCalledTimes(0);
});
+
it('should first refresh prometheus notifications and alerts during init', () => {
fixture.detectChanges();
expect(component.notifications[0].title).toBe('Sample title');
}));
});
+
+ describe('Sidebar', () => {
+ let notificationService: NotificationService;
+
+ beforeEach(() => {
+ notificationService = TestBed.get(NotificationService);
+ fixture.detectChanges();
+ });
+
+ it('should always close if sidebarSubject value is true', fakeAsync(() => {
+ // Closed before next value
+ expect(component.isSidebarOpened).toBeFalsy();
+ notificationService.sidebarSubject.next(true);
+ tick();
+ expect(component.isSidebarOpened).toBeFalsy();
+
+ // Opened before next value
+ component.isSidebarOpened = true;
+ expect(component.isSidebarOpened).toBeTruthy();
+ notificationService.sidebarSubject.next(true);
+ tick();
+ expect(component.isSidebarOpened).toBeFalsy();
+ }));
+
+ it('should toggle sidebar visibility if sidebarSubject value is false', () => {
+ // Closed before next value
+ expect(component.isSidebarOpened).toBeFalsy();
+ notificationService.sidebarSubject.next(false);
+ expect(component.isSidebarOpened).toBeTruthy();
+
+ // Opened before next value
+ component.isSidebarOpened = true;
+ expect(component.isSidebarOpened).toBeTruthy();
+ notificationService.sidebarSubject.next(false);
+ expect(component.isSidebarOpened).toBeFalsy();
+ });
+ });
});
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
+ HostBinding,
NgZone,
OnDestroy,
OnInit
import * as _ from 'lodash';
import * as moment from 'moment';
import { LocalStorage } from 'ngx-store';
+import { Subscription } from 'rxjs';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { SummaryService } from '../../../shared/services/summary.service';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotificationsSidebarComponent implements OnInit, OnDestroy {
+ @HostBinding('class.active') isSidebarOpened = false;
+
notifications: CdNotification[];
private interval: number;
+ private timeout: number;
executingTasks: ExecutingTask[] = [];
+ private sidebarSubscription: Subscription;
+ private notificationDataSubscription: Subscription;
+
icons = Icons;
// Tasks
@LocalStorage() last_task = '';
mutex = new Mutex();
+ simplebar = {
+ autoHide: false
+ };
+
constructor(
public notificationService: NotificationService,
private summaryService: SummaryService,
ngOnDestroy() {
window.clearInterval(this.interval);
+ window.clearTimeout(this.timeout);
+ if (this.sidebarSubscription) {
+ this.sidebarSubscription.unsubscribe();
+ }
+ if (this.notificationDataSubscription) {
+ this.notificationDataSubscription.unsubscribe();
+ }
}
ngOnInit() {
});
}
- this.notificationService.data$.subscribe((notifications: CdNotification[]) => {
- this.notifications = _.orderBy(notifications, ['timestamp'], ['desc']);
- this.cdRef.detectChanges();
+ this.notificationDataSubscription = this.notificationService.data$.subscribe(
+ (notifications: CdNotification[]) => {
+ this.notifications = _.orderBy(notifications, ['timestamp'], ['desc']);
+ this.cdRef.detectChanges();
+ }
+ );
+
+ this.sidebarSubscription = this.notificationService.sidebarSubject.subscribe((forceClose) => {
+ if (forceClose) {
+ this.isSidebarOpened = false;
+ } else {
+ this.isSidebarOpened = !this.isSidebarOpened;
+ }
+
+ window.clearTimeout(this.timeout);
+ this.timeout = window.setTimeout(() => {
+ this.cdRef.detectChanges();
+ }, 0);
});
this.summaryService.subscribe((data: any) => {
}
closeSidebar() {
- this.notificationService.toggleSidebar(true);
+ this.isSidebarOpened = false;
}
trackByFn(index: number) {
$color-nav-active-link-bg: $color-primary !default;
$color-nav-border-top-collapse: $color-white-gray !default;
+$navbar-height: 43px;
+$pwd-exp-height: 37.6px;
+
/*Helper*/
$color-helper-bg: $color-primary !default;