@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
193 lines (186 loc) • 9.45 kB
JavaScript
import { AssetHierarchyService, C8yTranslatePipe, ViewContext, BreadcrumbService, RouterService, GroupService, ContextRouteService, hookBreadcrumb } from '@c8y/ngx-components';
import * as i0 from '@angular/core';
import { InjectionToken, inject, Component, Injector, Injectable } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { NgStyle } from '@angular/common';
import { TranslateService } from '@ngx-translate/core';
import { gettext } from '@c8y/ngx-components/gettext';
import { cloneDeep } from 'lodash-es';
import { AssetNodeService } from '@c8y/ngx-components/module-federation-exports/assets-navigator';
const GROUP_BREADCRUMB_CONTEXT_DATA = new InjectionToken('GROUP_BREADCRUMB_CONTEXT_DATA');
const GROUP_BREADCRUMB_FACTORY = new InjectionToken('GROUP_BREADCRUMB_FACTORY');
class GroupBreadcrumbEllipsisComponent {
constructor() {
this.isLoading = false;
this.assetHierarchyService = inject(AssetHierarchyService);
this.contextData = inject(GROUP_BREADCRUMB_CONTEXT_DATA);
this.factory = inject(GROUP_BREADCRUMB_FACTORY);
}
async onClick() {
this.isLoading = true;
const ancestorPaths = await this.assetHierarchyService.getAncestorPaths(this.contextData.id);
this.factory.setAncestorPaths(ancestorPaths);
this.isLoading = false;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupBreadcrumbEllipsisComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: GroupBreadcrumbEllipsisComponent, isStandalone: true, selector: "c8y-group-breadcrumb-ellipsis", ngImport: i0, template: "<button\n class=\"btn-clean btn btn-xs p-t-0 p-b-0\"\n [ngStyle]=\"{ cursor: isLoading ? 'wait' : 'pointer' }\"\n title=\"{{ 'Show all paths' | translate }}\"\n type=\"button\"\n (click)=\"!isLoading && onClick()\"\n>\n ...\n</button>\n", dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupBreadcrumbEllipsisComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-group-breadcrumb-ellipsis', standalone: true, imports: [NgStyle, C8yTranslatePipe], template: "<button\n class=\"btn-clean btn btn-xs p-t-0 p-b-0\"\n [ngStyle]=\"{ cursor: isLoading ? 'wait' : 'pointer' }\"\n title=\"{{ 'Show all paths' | translate }}\"\n type=\"button\"\n (click)=\"!isLoading && onClick()\"\n>\n ...\n</button>\n" }]
}] });
class GroupBreadcrumbFactory {
constructor() {
this.SUPPORTED_CONTEXTS = [ViewContext.Device, ViewContext.Group];
this.GROUP_ICON = 'c8y-group';
this.DEVICE_ICON = 'data-transfer';
this.deviceDefaultLabel = gettext('Device {{id}}');
this.currentBreadcrumbData = null;
this.breadcrumbService = inject(BreadcrumbService);
this.routerService = inject(RouterService);
this.groupService = inject(GroupService);
this.translateService = inject(TranslateService);
this.injector = inject(Injector);
this.contextRouteService = inject(ContextRouteService);
this.assetNodeService = inject(AssetNodeService);
}
async get(activatedRoute) {
const routeData = this.contextRouteService.getContextData(activatedRoute);
const context = routeData?.context;
const contextData = routeData?.contextData;
// Only show breadcrumbs for Device/Group contexts with contextData
if (!this.SUPPORTED_CONTEXTS.includes(context) || !contextData) {
return null;
}
// Check if same context as before
const isSameContext = this.currentBreadcrumbData?.contextData?.id === contextData.id;
// If same context and has ancestor paths loaded, return full breadcrumb
if (isSameContext && this.currentBreadcrumbData?.ancestorPaths) {
return this.buildFullBreadcrumb(this.currentBreadcrumbData.ancestorPaths);
}
// If same context but no ancestor paths, return existing ellipsis breadcrumb
if (isSameContext && this.currentBreadcrumbData?.breadcrumbs) {
return this.currentBreadcrumbData.breadcrumbs;
}
// New context - determine if root or nested
const rootNodesResult = await firstValueFrom(this.assetNodeService.rootGroups$);
const rootNodes = rootNodesResult.data || [];
const isRootNode = rootNodes.some(node => node.id === contextData.id);
const icon = await this.getIcon(contextData);
// Root node: simple breadcrumb
if (isRootNode) {
const breadcrumbs = [
{
items: [
{
label: gettext('Groups'),
path: 'group',
icon: this.GROUP_ICON
},
{
label: contextData.name,
icon,
path: ''
}
]
}
];
this.currentBreadcrumbData = {
contextData: cloneDeep(contextData),
breadcrumbs
};
return breadcrumbs;
}
// Nested node: breadcrumb with ellipsis component
const ellipsisInjector = Injector.create({
parent: this.injector,
providers: [
{ provide: GROUP_BREADCRUMB_CONTEXT_DATA, useValue: contextData },
{ provide: GROUP_BREADCRUMB_FACTORY, useValue: this }
]
});
const breadcrumbs = [
{
injector: ellipsisInjector,
items: [
{
label: gettext('Groups'),
path: 'group',
icon: this.GROUP_ICON
},
{
component: GroupBreadcrumbEllipsisComponent
},
{
label: contextData.name ||
this.translateService.instant(this.deviceDefaultLabel, { id: contextData.id }),
icon,
path: ''
}
]
}
];
this.currentBreadcrumbData = {
contextData: cloneDeep(contextData),
breadcrumbs
};
return breadcrumbs;
}
setAncestorPaths(ancestorPaths) {
if (!this.currentBreadcrumbData) {
return;
}
this.currentBreadcrumbData.ancestorPaths = ancestorPaths;
this.breadcrumbService.refresh(); // will trigger factory `get` once again
}
async buildFullBreadcrumb(ancestorPaths) {
const converted = await this.convertToBreadcrumbItems(ancestorPaths);
const sorted = this.sortBreadcrumbItems(converted);
const breadcrumbs = sorted.map(bc => ({
items: [
{
label: gettext('Groups'),
path: 'group',
icon: this.GROUP_ICON
},
...bc.map((item, index) => ({
...item,
path: index === bc.length - 1 ? undefined : item.path
}))
],
forceDropdownOpen: sorted.length > 1
}));
this.currentBreadcrumbData.breadcrumbs = breadcrumbs;
return breadcrumbs;
}
async convertToBreadcrumbItems(ancestorPaths) {
return Promise.all(ancestorPaths.map(async (path) => Promise.all(path.map(async (managedObject) => ({
label: managedObject.name ||
this.translateService.instant(this.deviceDefaultLabel, { id: managedObject.id }),
path: '/' + this.routerService.getHref(managedObject, ''),
icon: await this.getIcon(managedObject)
})))));
}
sortBreadcrumbItems(breadcrumbItems) {
const breadcrumbs = breadcrumbItems.map(items => ({ items }));
const sorted = this.breadcrumbService.sortByPreferredPath(breadcrumbs);
return sorted.map(breadcrumb => breadcrumb.items);
}
async getIcon(managedObject) {
if (this.groupService.isDevice(managedObject)) {
return this.DEVICE_ICON;
}
return this.groupService.getIcon(managedObject);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupBreadcrumbFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupBreadcrumbFactory }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupBreadcrumbFactory, decorators: [{
type: Injectable
}] });
const groupBreadcrumbsProviders = [hookBreadcrumb(GroupBreadcrumbFactory)];
/**
* Generated bundle index. Do not edit.
*/
export { groupBreadcrumbsProviders };
//# sourceMappingURL=c8y-ngx-components-group-breadcrumbs.mjs.map