Skip to content

Commit

Permalink
feat(admin-ui): Allow status badges to be defined for NavMenuItems
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed May 5, 2020
1 parent b3411f2 commit 97e209c
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
[class.collapsible]="section.collapsible"
*vdrIfPermissions="section.requiresPermission"
>
<ng-container *ngIf="navBuilderService.sectionBadges[section.id] | async as sectionBadge">
<div *ngIf="sectionBadge !== 'none'" class="status-badge" [class]="sectionBadge"></div>
</ng-container>
<input [id]="section.id" type="checkbox" [checked]="section.collapsedByDefault" />
<label [for]="section.id">{{ section.label | translate }}</label>
<ul class="nav-list">
Expand All @@ -17,6 +20,13 @@
[routerLink]="getRouterLink(item)"
routerLinkActive="active"
>
<ng-container *ngIf="item.statusBadge | async as itemBadge">
<div
*ngIf="itemBadge.type !== 'none'"
class="status-badge"
[class]="itemBadge.type"
></div>
</ng-container>
<clr-icon [attr.shape]="item.icon || 'block'" size="20"></clr-icon>
{{ item.label | translate }}
</a>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "variables";
@import 'variables';

:host {
// flex: 0 0 auto;
Expand All @@ -14,3 +14,38 @@ nav.sidenav {
.nav-list clr-icon {
margin-right: 12px;
}

.nav-group,
.nav-link {
position: relative;
}

.status-badge {
width: 10px;
height: 10px;
position: absolute;
border-radius: 50%;
border: 1px solid $color-grey-200;

&.info {
background-color: $color-primary-600;
}
&.success {
background-color: $color-success-500;
}
&.warning {
background-color: $color-warning-500;
}
&.error {
background-color: $color-error-400;
}
}

.nav-group .status-badge {
left: 10px;
top: 6px;
}
.nav-link .status-badge {
left: 25px;
top: 3px;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ import { Observable } from 'rxjs';
import { DataService } from '../../data/providers/data.service';
import { NotificationService } from '../notification/notification.service';

export type NavMenuBadgeType = 'none' | 'info' | 'success' | 'warning' | 'error';

/**
* A color-coded notification badge which will be displayed by the
* NavMenuItem's icon.
*/
export interface NavMenuBadge {
type: NavMenuBadgeType;
/**
* If true, the badge will propagate to the NavMenuItem's
* parent section, displaying a notification badge next
* to the section name.
*/
propagateToSection?: boolean;
}

/**
* A NavMenuItem is a menu item in the main (left-hand side) nav
* bar.
Expand All @@ -15,6 +31,7 @@ export interface NavMenuItem {
onClick?: (event: MouseEvent) => void;
icon?: string;
requiresPermission?: string;
statusBadge?: Observable<NavMenuBadge>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { APP_INITIALIZER, Injectable, Provider } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';

import { Permission } from '../../common/generated-types';

import { ActionBarItem, NavMenuItem, NavMenuSection, RouterLinkDefinition } from './nav-builder-types';
import {
ActionBarItem,
NavMenuBadgeType,
NavMenuItem,
NavMenuSection,
RouterLinkDefinition,
} from './nav-builder-types';

/**
* @description
Expand Down Expand Up @@ -126,6 +133,7 @@ export function addActionBarItem(config: ActionBarItem): Provider {
export class NavBuilderService {
navMenuConfig$: Observable<NavMenuSection[]>;
actionBarConfig$: Observable<ActionBarItem[]>;
sectionBadges: { [sectionId: string]: Observable<NavMenuBadgeType> } = {};

private initialNavMenuConfig$ = new BehaviorSubject<NavMenuSection[]>([]);
private addedNavMenuSections: Array<{ config: NavMenuSection; before?: string }> = [];
Expand Down Expand Up @@ -195,19 +203,19 @@ export class NavBuilderService {
const itemAdditions$ = of(this.addedNavMenuItems);

const combinedConfig$ = combineLatest(this.initialNavMenuConfig$, sectionAdditions$).pipe(
map(([initalConfig, additions]) => {
map(([initialConfig, additions]) => {
for (const { config, before } of additions) {
if (!config.requiresPermission) {
config.requiresPermission = Permission.Authenticated;
}
const index = initalConfig.findIndex(c => c.id === before);
const index = initialConfig.findIndex(c => c.id === before);
if (-1 < index) {
initalConfig.splice(index, 0, config);
initialConfig.splice(index, 0, config);
} else {
initalConfig.push(config);
initialConfig.push(config);
}
}
return initalConfig;
return initialConfig;
}),
shareReplay(1),
);
Expand All @@ -219,9 +227,7 @@ export class NavBuilderService {
if (!section) {
// tslint:disable-next-line:no-console
console.error(
`Could not add menu item "${item.config.id}", section "${
item.sectionId
}" does not exist`,
`Could not add menu item "${item.config.id}", section "${item.sectionId}" does not exist`,
);
} else {
const index = section.items.findIndex(i => i.id === item.before);
Expand All @@ -232,6 +238,32 @@ export class NavBuilderService {
}
}
}

// Aggregate any badges defined for the nav items in each section
for (const section of sections) {
const itemBadgeStatuses = section.items
.map(i => i.statusBadge)
.filter(notNullOrUndefined);
this.sectionBadges[section.id] = combineLatest(itemBadgeStatuses).pipe(
map(badges => {
const propagatingBadges = badges.filter(b => b.propagateToSection);
if (propagatingBadges.length === 0) {
return 'none';
}
const statuses = propagatingBadges.map(b => b.type);
if (statuses.includes('error')) {
return 'error';
} else if (statuses.includes('warning')) {
return 'warning';
} else if (statuses.includes('info')) {
return 'info';
} else {
return 'none';
}
}),
);
}

return sections;
}),
);
Expand Down

0 comments on commit 97e209c

Please sign in to comment.