Skip to content

Commit

Permalink
feat(admin-ui): Improved control over ActionBar buttons
Browse files Browse the repository at this point in the history
This commit implements setting disabled and visible states, as well
as providing the `Injector` instance to the click handler.
  • Loading branch information
michaelbromley committed Sep 12, 2023
1 parent ba2026e commit 065a2b4
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Injector } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';

import { ActionBarLocationId, UIExtensionLocationId } from '../../common/component-registry-types';
import { ActionBarLocationId } from '../../common/component-registry-types';
import { DataService } from '../../data/providers/data.service';
import { NotificationService } from '../notification/notification.service';

Expand Down Expand Up @@ -74,12 +75,18 @@ export interface NavMenuSection {
*
* @docsCategory action-bar
*/
export interface OnClickContext {
export interface ActionBarContext {
route: ActivatedRoute;
injector: Injector;
dataService: DataService;
notificationService: NotificationService;
}

export interface ActionBarButtonState {
disabled: boolean;
visible: boolean;
}

/**
* @description
* A button in the ActionBar area at the top of one of the list or detail views.
Expand All @@ -90,8 +97,12 @@ export interface ActionBarItem {
id: string;
label: string;
locationId: ActionBarLocationId;
/**
* @deprecated - use `buttonState` instead.
*/
disabled?: Observable<boolean>;
onClick?: (event: MouseEvent, context: OnClickContext) => void;
buttonState?: (context: ActionBarContext) => Observable<ActionBarButtonState>;
onClick?: (event: MouseEvent, context: ActionBarContext) => void;
routerLink?: RouterLinkDefinition;
buttonColor?: 'primary' | 'success' | 'warning';
buttonStyle?: 'solid' | 'outline' | 'link';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<vdr-ui-extension-point [locationId]="locationId" api="actionBar" [leftPx]="-24">
<ng-container *ngFor="let item of items$ | async">
<button
*vdrIfPermissions="item.requiresPermission"
[routerLink]="getRouterLink(item)"
[disabled]="item.disabled ? (item.disabled | async) : false"
(click)="handleClick($event, item)"
[ngClass]="getButtonStyles(item)"
class="mr-2"
>
<clr-icon *ngIf="item.icon" [attr.shape]="item.icon"></clr-icon>
{{ item.label | translate }}
</button>
<ng-container *ngIf="buttonStates[item.id] | async as buttonState">
<button
*vdrIfPermissions="item.requiresPermission"
[routerLink]="getRouterLink(item)"
[class.hidden]="buttonState.visible === false"
[disabled]="buttonState.disabled || (item.disabled ? (item.disabled | async) : false)"
(click)="handleClick($event, item)"
[ngClass]="getButtonStyles(item)"
class="mr-2"
>
<clr-icon *ngIf="item.icon" [attr.shape]="item.icon"></clr-icon>
{{ item.label | translate }}
</button>
</ng-container>
</ng-container>
</vdr-ui-extension-point>
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:host {
display: inline-block;
}

button.hidden {
display: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ import {
ChangeDetectionStrategy,
Component,
HostBinding,
Injector,
Input,
OnChanges,
OnInit,
SimpleChanges,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { assertNever } from '@vendure/common/lib/shared-utils';
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { BehaviorSubject, combineLatest, mergeAll, Observable, of } from 'rxjs';
import { map, tap } from 'rxjs/operators';

import { ActionBarLocationId } from '../../../common/component-registry-types';
import { DataService } from '../../../data/providers/data.service';
import { ActionBarItem } from '../../../providers/nav-builder/nav-builder-types';
import {
ActionBarButtonState,
ActionBarContext,
ActionBarItem,
} from '../../../providers/nav-builder/nav-builder-types';
import { NavBuilderService } from '../../../providers/nav-builder/nav-builder.service';
import { NotificationService } from '../../../providers/notification/notification.service';

Expand All @@ -30,18 +35,33 @@ export class ActionBarItemsComponent implements OnInit, OnChanges {
locationId: ActionBarLocationId;

items$: Observable<ActionBarItem[]>;
buttonStates: { [id: string]: Observable<ActionBarButtonState> } = {};
private locationId$ = new BehaviorSubject<string>('');

constructor(
private navBuilderService: NavBuilderService,
private route: ActivatedRoute,
private dataService: DataService,
private notificationService: NotificationService,
private injector: Injector,
) {}

ngOnInit() {
this.items$ = combineLatest(this.navBuilderService.actionBarConfig$, this.locationId$).pipe(
map(([items, locationId]) => items.filter(config => config.locationId === locationId)),
tap(items => {
const context = this.createContext();
for (const item of items) {
const buttonState$ =
typeof item.buttonState === 'function'
? item.buttonState(context)
: of({
disabled: false,
visible: true,
});
this.buttonStates[item.id] = buttonState$;
}
}),
);
}

Expand All @@ -53,11 +73,7 @@ export class ActionBarItemsComponent implements OnInit, OnChanges {

handleClick(event: MouseEvent, item: ActionBarItem) {
if (typeof item.onClick === 'function') {
item.onClick(event, {
route: this.route,
dataService: this.dataService,
notificationService: this.notificationService,
});
item.onClick(event, this.createContext());
}
}

Expand Down Expand Up @@ -90,4 +106,13 @@ export class ActionBarItemsComponent implements OnInit, OnChanges {
return '';
}
}

private createContext(): ActionBarContext {
return {
route: this.route,
injector: this.injector,
dataService: this.dataService,
notificationService: this.notificationService,
};
}
}

0 comments on commit 065a2b4

Please sign in to comment.