@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
1,179 lines (1,156 loc) • 70.1 kB
JavaScript
import * as i0 from '@angular/core';
import { NgZone, Injectable, NgModule, Inject, inject, Optional, ChangeDetectionStrategy, Component } from '@angular/core';
import { setAngularJSGlobal, downgradeComponent, downgradeInjectable } from '@angular/upgrade/static';
import * as i2 from '@c8y/ngx-components';
import { DatePipe, ViewContext, EmptyComponent, gettext, AppStateService, RouterService, ActionService, PluginsResolveService, TenantUiService, RouterModule, hookNavigator, hookTab, hookActionBar, hookAction, hookBreadcrumb, hookDocs, BootstrapComponent, UserTotpRevokeComponent, DataGridComponent, LoadingComponent, RangeDisplayComponent, HelpComponent, HighlightComponent, EmptyStateComponent, PasswordInputComponent, HOOK_PATTERN_MESSAGES, HeaderService, AlertService, UserMenuService, DocsService, PasswordService, CachedLocaleDictionaryService, GlobalConfigService, ModalService, GainsightService, FilesService, ServiceRegistry, AssetLinkPipe, PropertyValueTransformService, FeatureCacheService, DateFormatService, NavigatorNodeRoot, getActivatedRoute, DynamicDatapointsResolver, DynamicManagedObjectResolver, C8yTranslateModule, hookComponent } from '@c8y/ngx-components';
import { UpgradedServicesModule } from '@c8y/ngx-components/upgrade/upgraded-services';
import * as angular from 'angular';
import { map, unary, find, forEach, startsWith, isArray, assign, every, pick, property, some, get } from 'lodash-es';
import { ReplaySubject, BehaviorSubject, merge, of, combineLatest, Observable, from, fromEventPattern, Subject, defer, debounceTime as debounceTime$1 } from 'rxjs';
import { filter, take, delay, map as map$1, debounceTime, switchMap, startWith, merge as merge$1, shareReplay } from 'rxjs/operators';
import { ResolveEnd, ActivationEnd, Router } from '@angular/router';
import { BasicAuth, FetchClient, QueriesUtil } from '@c8y/client';
import { AppLogsAutoRefreshComponent } from '@c8y/ngx-components/app-logs';
import { DatapointSelectionListComponent, DatapointSelectorService } from '@c8y/ngx-components/datapoint-selector';
import { PaginationComponent } from 'ngx-bootstrap/pagination';
import { RolesAssetTreeComponent } from '@c8y/ngx-components/user-roles';
import { PlatformConfigurationFormComponent } from '@c8y/ngx-components/platform-configuration';
import { WidgetPreviewWrapperComponent, ContextDashboardService } from '@c8y/ngx-components/context-dashboard';
import { ApiService } from '@c8y/ngx-components/api';
import { DeviceGridService } from '@c8y/ngx-components/device-grid';
import { DeviceTypeDetailEditedService } from '@c8y/ngx-components/device-protocols';
import * as i1 from '@ngx-translate/core';
import { TranslateService } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
class AbsoluteDateService {
constructor(datePipe) {
this.datePipe = datePipe;
}
getFilter() {
return (value, format = 'medium', timezone, locale) => this.datePipe.transform(value, format, timezone, locale);
}
}
function absoluteDateServiceFactory(datePipe) {
return new AbsoluteDateService(datePipe).getFilter();
}
const absoluteDateServiceProvider = {
provide: AbsoluteDateService,
useFactory: absoluteDateServiceFactory,
deps: [DatePipe]
};
var ViewContextLegacyParameter;
(function (ViewContextLegacyParameter) {
ViewContextLegacyParameter["Device"] = "deviceId";
ViewContextLegacyParameter["Group"] = "groupId";
ViewContextLegacyParameter["User"] = "userId";
ViewContextLegacyParameter["Application"] = "applicationId";
ViewContextLegacyParameter["Microservice"] = "applicationId";
ViewContextLegacyParameter["SubscribedApplications"] = "applicationId";
ViewContextLegacyParameter["Tenant"] = "tenantId";
ViewContextLegacyParameter["Service"] = "deviceId";
ViewContextLegacyParameter["Simulators"] = "deviceId"; // required to hook the Alarms tab to a Simulator view
})(ViewContextLegacyParameter || (ViewContextLegacyParameter = {}));
function c8yViewsProvider($routeProvider, c8yTabsProvider, c8yPathUtils) {
'ngInject';
const viewMap = {};
const contextViews = new ReplaySubject();
return {
when,
$get() {
return {
contextViews,
when(path, cfg) {
return when(path, cfg, true);
},
getByPath,
prefixWithSlash
};
}
};
/**
* @ngdoc function
* @name when
* @methodOf c8y.ui.provider:c8yViewsProvider
*
* @description
* Defines a view for given route.
* If multiple views are defined for a single route then there will be a separate tab for each view available when user visits that route.
*
* @param path Target route.
* @param cfg View configuration object with the following properties:
*
* - **name** - `string` - View's name (in case of multiple views at single route this will be displayed as tab's title).
* - **priority** - `integer` - View's priority (in case of multiple views at single route this will determine the position of view's tab in the tabs stack).
* - **icon** - `string` - Font Awesome icon name for the view (displayed on the tab's header).
* - **showIf** - `function` - Function returning boolean value indicating whether to show a tab for the view or not.
* - **templateUrl** - `string` - Path to the template to use for displaying the view.
*
* You can also provide other view options - the same as available for standard {@link https://docs.angularjs.org/api/ngRoute/provider/$routeProvider $routeProvider} in AngularJS.
*
* ```html
* The following example demonstrates how to add a new view to device details route
* (which will be displayed as a tab if other views are assigned to the same route):
* <pre>
* c8yViewsProvider.when('/device/:deviceId', {
* name: 'Tracking',
* templateUrl: ':::PLUGIN_PATH:::/views/index.html',
* icon: 'crosshairs',
* showIf: ['$routeParams', 'c8yDevices', function ($routeParams, c8yDevices) {
* var deviceId = $routeParams.deviceId;
* return c8yDevices.detailCached(deviceId).then(function (res) {
* var device = res.data;
* return device && (device.c8y_MotionTracking || device.c8y_Geofence);
* });
* }]
* });
* </pre>
* ```
*/
function when(path, cfg, runPhase) {
const newPath = prefixWithSlash(path);
cfg.resolve = cfg.resolve || {};
// eslint-disable-next-line no-underscore-dangle
cfg.resolve.__c8y_locales = [
'c8yLocales',
c8yLocales => {
return c8yLocales.initDone;
}
];
let currentCfg = viewMap[newPath];
const originalPath = newPath;
if (!cfg.name) {
// console.warn('View name not defined');
}
if (!currentCfg) {
viewMap[newPath] = [];
currentCfg = viewMap[newPath];
}
const upgradedContext = Object.keys(ViewContext)
.map(key => ({
key,
isUpgrade: prefixWithSlash(ViewContext[key].replace('id', ViewContextLegacyParameter[key])) === path
}))
.find(({ isUpgrade }) => isUpgrade);
if (upgradedContext) {
currentCfg.push(cfg);
cfg.path = newPath;
const p = c8yPathUtils.appendSegment(originalPath.replace(path, ''), cfg.name);
contextViews.next({
...cfg,
path: cfg.name ? p.substring(1) : '',
contextKey: upgradedContext.key,
runPhase
});
cfg.showIf = undefined;
if (cfg.name) {
cfg.path = c8yPathUtils.appendSegment(originalPath, cfg.name);
}
}
else {
if (currentCfg.length === 1) {
const [existingConfig] = currentCfg;
existingConfig.path = c8yPathUtils.appendSegment(originalPath, existingConfig.name);
existingConfig.tab = createTab(originalPath, existingConfig);
$routeProvider.when(existingConfig.path, existingConfig);
}
currentCfg.push(cfg);
cfg.path = newPath;
if (currentCfg.length > 1) {
cfg.path = c8yPathUtils.appendSegment(originalPath, cfg.name);
createTab(originalPath, cfg);
$routeProvider.when(prefixWithSlash(originalPath), {
resolveRedirectTo($route, $q, c8yUiUtil, c8yTabs, gettextCatalog) {
'ngInject';
const sortedCurrentCfg = c8yTabsProvider.sortTabsViews(currentCfg, gettextCatalog);
const params = $route.current.pathParams;
return $q
.all(map(sortedCurrentCfg, unary(c8yUiUtil.configureVisibility)))
.then(views => {
const first = find(views, 'show');
let url = first.path;
forEach(params, (val, key) => {
url = url.replace(`:${key}`, val);
});
c8yTabs.redirectedViewPath = url;
return url;
});
}
});
}
}
return $routeProvider.when(prefixWithSlash(cfg.path), cfg);
}
function getByPath(path) {
return viewMap[prefixWithSlash(path)];
}
function createTab(path, cfg) {
c8yTabsProvider.addTab(path, cfg);
}
function prefixWithSlash(path) {
const prefix = startsWith(path, '/') ? '' : '/';
return prefix + path;
}
}
class BridgeService {
constructor(injector, appState, router, ngZone, routerService, actionService, plugins) {
this.injector = injector;
this.appState = appState;
this.router = router;
this.ngZone = ngZone;
this.routerService = routerService;
this.actionService = actionService;
this.$liveTabs = new BehaviorSubject([]);
this.initialNavigationDone = false;
this.fixE2eIssues();
this.$ng1RouteChangeSuccess = this.fromNg1Event(this.injector.get('$rootScope'), '$routeChangeSuccess');
this.$ng1RouteChangeStart = this.fromNg1Event(this.injector.get('$rootScope'), '$routeChangeStart');
this.hookLanguage();
this.hookTab();
this.hookNavigator();
this.hookUserMenu();
this.hookViewProvider();
this.hookRoute();
plugins.allPluginsLoaded$
.pipe(filter(tmp => !!tmp), take(1), delay(1))
.subscribe(() => {
this.initialNavigationDone = true;
this.router.initialNavigation();
});
this.ng1Routes();
}
/**
* Ensure that angularjs routes are not using any
* secondary router outlets
*/
hookRoute() {
this.router.events
.pipe(filter(event => event instanceof ResolveEnd), map$1((event) => event.state.root.firstChild), filter(route => route && route.routeConfig && route.routeConfig.path === '**'))
.subscribe((event) => {
if (event.root.children.length > 1) {
window.location.hash = event.root.children[0].url.toString();
}
});
}
hookViewProvider() {
const c8yViews = this.injector.get('c8yViews');
// fix to trigger an angularjs route change success
// event on context route match to make legacy
// view-providers resolve.
c8yViews.when('/device/:id', {
template: ''
});
c8yViews.when('/group/:id', {
template: ''
});
c8yViews.contextViews.subscribe(cfg => this.addRoute(cfg));
}
addRoute(cfg) {
this.routerService.addRoute({
label: cfg.label || cfg.name,
path: cfg.path,
icon: cfg.icon,
context: ViewContext[cfg.contextKey],
priority: cfg.priority,
component: EmptyComponent,
data: {
showIf: cfg.showIf
? ngxRoute => {
const params = {
...ngxRoute.params,
[ViewContextLegacyParameter[cfg.contextKey]]: ngxRoute.params.id
};
const showIfResult = this.injector.invoke(cfg.showIf, undefined, {
$routeParams: params
});
// make sure showIf result is a promise with boolean result:
return this.injector.get('$q').when(showIfResult).then(Boolean);
}
: undefined
},
...(cfg.featureId && { featureId: cfg.featureId })
});
if (cfg.runPhase) {
this.routerService.refresh();
}
}
ng1Routes() {
const template = '';
const fallbackRoutes = [];
for (const context in ViewContext) {
if (ViewContext[context] !== ViewContext.Alarms) {
const path = ViewContext[context].match(/(\w+)\//)[1];
const regexp = new RegExp(`^/${path}/(?:([^/]+)).*$`);
fallbackRoutes.push({
keys: [{ name: ViewContextLegacyParameter[context], optional: false }],
regexp,
template
});
}
}
/**
* When asset detail routes (/device/:id, /group/:id) are matched in Angular Router, ngRoute in
* angular.js must also have matching generic routes so that the ids can be extracted from the paths and
* injected in multiple calls (showIf, c8yActions, etc) as properties of $routeParams.
*
* The function in src/ngRoute/route.js (angular.js) where the routes are matched is called parseRoute(). This
* function calls angular.forEach and in turn this function checks for the presence of a forEach method before
* trying object key iteration.
* By attaching a non enumerable forEach method to the routes object we guarantee that the fallback generic routes
* are only matched after any other registered through $routeProvider.when.
*/
const $route = this.injector.get('$route');
Object.defineProperty($route.routes, 'forEach', {
// make non enumerable
value: function forEach(iterator, context) {
// tslint:disable-next-line: forin
for (const key in this) {
iterator.call(context, this[key], key, this);
}
fallbackRoutes.forEach(r => iterator.call(context, r));
},
configurable: true
});
/**
* Some functions use the current context. As some parts are upgraded and some not, the following updates the
* angularjs getContext function to resolve always the right context.
*/
const c8yUiUtil = this.injector.get('c8yUiUtil');
const _getContext = c8yUiUtil.getContext;
this.router.events
.pipe(filter(event => event instanceof ActivationEnd))
.subscribe((event) => {
if (event.snapshot.routeConfig.path === '**') {
c8yUiUtil.getContext = _getContext;
}
else if (event.snapshot.data && event.snapshot.data.context) {
c8yUiUtil.getContext = () => {
return {
context: event.snapshot.data.context.replace('/:id', ''),
id: event.snapshot.data.contextData.id,
contextData: event.snapshot.data.contextData
};
};
}
else {
c8yUiUtil.getContext = () => ({ context: null, id: null });
}
});
}
fixE2eIssues() {
try {
const { ngZone } = this;
const { Utils } = window.org.cometd;
const timeoutFn = Utils.setTimeout;
// tslint:disable-next-line:only-arrow-functions
Utils.setTimeout = function (...args) {
return ngZone.runOutsideAngular(() => timeoutFn.apply(Utils, args));
};
}
catch (e) {
// do nothing
}
try {
const { ace } = window;
const editFn = ace.edit;
const { ngZone } = this;
// tslint:disable-next-line:only-arrow-functions
ace.edit = function (...args) {
return ngZone.runOutsideAngular(() => editFn.apply(ace, args));
};
}
catch (e) {
// do nothing
}
}
hookLanguage() {
let first = true;
this.appState
.map(store => store.lang)
.subscribe(lang => {
this.injector.get('c8yLocales').switchToLanguage(lang);
if (!first) {
this.injector.get('$rootScope').$apply();
}
first = false;
});
}
hookTab() {
// Just for instantiation of the c8yAction service
this.injector.get('c8yActions');
const $location = this.injector.get('$location');
const c8yTabs = this.injector.get('c8yTabs');
let liveTabs = [];
c8yTabs.addTab = tab => {
liveTabs.push({
...tab,
label: tab.label || tab.name,
path: decodeURIComponent(tab.path)
});
this.$liveTabs.next(liveTabs);
};
this.$ng1RouteChangeStart.subscribe(() => {
liveTabs = [];
this.$liveTabs.next(liveTabs);
});
this.$ng1RouteChangeSuccess.subscribe(() => {
const path = $location.path();
if (this.router.url !== path && this.initialNavigationDone) {
this.router.navigate(path === '/' ? '' : path.split('/'), {
queryParams: $location.search(),
skipLocationChange: true
});
}
if (this.actionService) {
this.actionService.refresh();
}
});
this.$routeChanges = merge(this.$ng1RouteChangeSuccess, this.fromNg1Event(c8yTabs, c8yTabs.EVENT_UPDATE), of(1)).pipe(debounceTime(100));
}
hookNavigator() {
this.navigationNodes$ = this.injector.get('c8yNavigator').rootNodes$;
}
getTabs() {
const onlyVisible = ({ show }) => show;
const upgradeTab = tab => ({
...tab,
label: tab.label || tab.name,
path: decodeURIComponent(tab.path)
});
const routeTabs = this.$routeChanges.pipe(switchMap(() => {
const routes = this.injector.get('c8yTabs').routeTabs;
const visibilityPromise = Promise.all(routes.map(({ checkingVisibility }) => checkingVisibility));
return visibilityPromise.then(() => routes.filter(onlyVisible).map(upgradeTab));
}), startWith([]));
return combineLatest([routeTabs, this.$liveTabs]).pipe(map$1(([route, live]) => route.concat(live)));
}
getQuickLinks() {
const c8yQuickLinks = this.injector.get('c8yQuickLinks');
return c8yQuickLinks.list();
}
getActionBarItems() {
const c8yActionBar = this.injector.get('c8yActionBar');
const $rootScope = this.injector.get('$rootScope');
const getActionBarElements = () => c8yActionBar.elements.map(element => ({
priority: element.getAttribute('action-bar-priority') || 0,
template: element,
placement: element.getAttribute('action-bar-position') || 'right'
}));
return this.fromNg1Event($rootScope, 'c8yActionBarChanged').pipe(startWith(1), map$1(getActionBarElements));
}
getBreadcrumbs() {
const $location = this.injector.get('$location');
const c8yBreadcrumbs = this.injector.get('c8yBreadcrumbs');
const breadcrumbsUpdate$ = new Observable(subscriber => c8yBreadcrumbs.$on('update', () => subscriber.next()));
return breadcrumbsUpdate$.pipe(startWith(0), switchMap(() => {
const path = $location.path();
const breadcrumbs = c8yBreadcrumbs.get(path) || {};
const breadcrumbsData = this.resolveBreadcrumbsData(breadcrumbs.data);
return from(breadcrumbsData).pipe(map$1((value) => {
const liveBreadcrumbs = c8yBreadcrumbs.getLiveBreadcrumbs();
value = value.concat(liveBreadcrumbs);
return value.map(items => ({ items: items }));
}));
}));
}
resolveBreadcrumbsData(data) {
try {
return this.injector.invoke(data);
}
catch (ex) {
// empty
}
if (isArray(data)) {
return of([data]);
}
return of([]);
}
getSearch() {
const c8ySearch = this.injector.get('c8ySearch');
return c8ySearch.list().map(item => {
return {
icon: 'search',
name: item.name,
term: '',
onSearch() {
if (this.term) {
c8ySearch.search(this.term);
}
}
};
});
}
getActions() {
const registeredActions = this.injector.get('c8yActions').registeredActions;
return of(registeredActions
.filter(action => !action.hidden)
.map(action => ({
// The priority was reversed: Aligned it to dashboard, high first, low last.
priority: (action.priority || 0) * -1,
label: action.text,
icon: action.icon,
disabled: action.disabled,
action: () => {
this.injector.invoke(action.action, action);
}
})));
}
fromNg1Event(obj, evt) {
let stopListening;
function add(handler) {
stopListening = obj.$on(evt, handler);
}
return fromEventPattern(add, () => stopListening());
}
hookUserMenu() {
const userMenuService = this.injector.get('c8yUserMenuService');
const c8yAccessDenied = this.injector.get('c8yAccessDenied');
userMenuService.add({
icon: 'access',
priority: 10,
label: gettext('Access denied requests'),
click: c8yAccessDenied.showAccessDeniedRequestsList
});
}
}
function bridgeServiceFactory(injector, appState, router, ngZone, routerService, actionService, plugins) {
return new BridgeService(injector, appState, router, ngZone, routerService, actionService, plugins);
}
const bridgeServiceProvider = {
provide: BridgeService,
useFactory: bridgeServiceFactory,
deps: [
'$injector',
AppStateService,
Router,
NgZone,
RouterService,
ActionService,
PluginsResolveService
]
};
class Ng1ActionBarFactoryService {
constructor(bridge) {
this.bridge = bridge;
this.routeChanges$ = bridge.$routeChanges;
this.$ng1RouteChangeSuccess = bridge.$ng1RouteChangeSuccess;
}
get() {
return this.routeChanges$.pipe(switchMap(() => {
return this.bridge.getActionBarItems();
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionBarFactoryService, deps: [{ token: BridgeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionBarFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionBarFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }] });
class Ng1ActionFactoryService {
constructor(bridge, tabs) {
this.bridge = bridge;
this.tabs = tabs;
this.routeChanges$ = bridge.$routeChanges;
this.$location = bridge.injector.get('$location');
this.tabs.items$.subscribe(newTabs => this.handleTabsRedirect(newTabs));
}
handleTabsRedirect(tabs) {
/**
* This function is doing the same process as function redirect in the file
* modules/core/ui/navigation/tabs.provider.js
* That function is not run because bridge.service.ts overrides the method addTab where the redirect() was called.
*/
const redirectedTab = tabs.find(tab => tab.redirectedTo);
const [topPriorityTab] = tabs;
if (redirectedTab && !topPriorityTab.redirectedTo) {
this.$location.replace();
this.$location.path(topPriorityTab.path);
topPriorityTab.redirectedTo = true;
redirectedTab.redirectedTo = false;
}
}
get() {
return this.bridge.getActions();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionFactoryService, deps: [{ token: BridgeService }, { token: i2.TabsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1ActionFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }, { type: i2.TabsService }] });
class AuthBridgeService {
constructor(injector, basicAuth, fetchClient, appState, tenantUiService) {
this.injector = injector;
this.basicAuth = basicAuth;
this.fetchClient = fetchClient;
this.appState = appState;
this.tenantUiService = tenantUiService;
this.hookAuth();
}
updateBasicAuth(credentials) {
const { headers } = this.fetchClient.getFetchOptions({});
if (headers.Authorization) {
const token = headers.Authorization.match(/basic\s(.*)$/i)[1];
if (token) {
this.basicAuth.updateCredentials(credentials);
this.fetchClient.setAuth(this.basicAuth);
}
}
}
hookAuth() {
this.appState.currentUser.subscribe(user => {
if (!user) {
this.injector.get('$rootScope').$emit('authStateChange', { hasAuth: false });
return;
}
this.injector.get('c8yAuth').headers = () => this.fetchClient.getFetchOptions({}).headers;
const { headers } = this.fetchClient.getFetchOptions({});
const authorizationHeader = headers.Authorization;
if (typeof authorizationHeader === 'string' && authorizationHeader.startsWith('Basic')) {
const matches = authorizationHeader.match(/basic\s(.*)$/i);
const token = matches && matches[1];
if (token) {
this.setToken(token, headers.tfatoken);
}
}
else if (typeof authorizationHeader === 'string' &&
authorizationHeader.startsWith('Bearer')) {
this.setToken(undefined, headers.tfatoken, 'Bearer');
}
else {
this.setToken(undefined, headers.tfatoken, 'Oauth');
}
this.injector.get('$rootScope').$emit('authStateChange', { hasAuth: true });
});
}
setToken(token, tfa, type = 'Basic') {
const c8yAuth = this.injector.get('c8yAuth');
if (type === 'Basic') {
c8yAuth.onSetToken({ token, type });
if (tfa) {
c8yAuth.setTFAToken(tfa);
}
}
else {
c8yAuth.authReady();
}
}
getPreferredLoginOption() {
return this.tenantUiService.getPreferredLoginOption(this.appState.state.loginOptions);
}
}
function authBridgeServiceFactory(injector, basicAuth, fetchClient, appState, tenantUiService) {
return new AuthBridgeService(injector, basicAuth, fetchClient, appState, tenantUiService);
}
const authBridgeServiceProvider = {
provide: AuthBridgeService,
useFactory: authBridgeServiceFactory,
deps: ['$injector', BasicAuth, FetchClient, AppStateService, TenantUiService]
};
class Ng1BreadcrumbFactoryService {
constructor(bridge) {
this.bridge = bridge;
this.trigger = new ReplaySubject(1);
this.breadcrumbs = this.trigger.pipe(debounceTime(100), switchMap(() => {
return this.bridge.getBreadcrumbs();
}));
}
get() {
this.trigger.next();
return this.breadcrumbs;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1BreadcrumbFactoryService, deps: [{ token: BridgeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1BreadcrumbFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1BreadcrumbFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }] });
class Ng1DocsFactoryService {
constructor(bridge) {
this.bridge = bridge;
this.links = this.bridge.getQuickLinks();
this.links.then(list => {
list.map(el => {
el.type = el.type || 'quicklink';
return el;
});
});
}
get() {
return this.links;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1DocsFactoryService, deps: [{ token: BridgeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1DocsFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1DocsFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }] });
class Ng1NodesFactoryService {
constructor(bridge) {
this.bridge = bridge;
}
get() {
return this.bridge.navigationNodes$;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1NodesFactoryService, deps: [{ token: BridgeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1NodesFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1NodesFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }] });
class Ng1SmartRulesService {
}
function SmartRulesServiceFactory(injector) {
return injector.get('smartRulesSvc');
}
const smartRulesServiceProvider = {
provide: Ng1SmartRulesService,
useFactory: SmartRulesServiceFactory,
deps: ['$injector']
};
class Ng1TabsFactoryService {
constructor(bridge) {
this.bridge = bridge;
this.tabsObservable = bridge.getTabs();
}
get() {
return this.tabsObservable;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1TabsFactoryService, deps: [{ token: BridgeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1TabsFactoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Ng1TabsFactoryService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: BridgeService }] });
setAngularJSGlobal(angular);
class UpgradeModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpgradeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: UpgradeModule, imports: [RouterModule, UpgradedServicesModule] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpgradeModule, providers: [
absoluteDateServiceProvider,
bridgeServiceProvider,
authBridgeServiceProvider,
smartRulesServiceProvider,
hookNavigator(Ng1NodesFactoryService),
hookTab(Ng1TabsFactoryService),
hookActionBar(Ng1ActionBarFactoryService),
hookAction(Ng1ActionFactoryService),
hookBreadcrumb(Ng1BreadcrumbFactoryService),
hookDocs(Ng1DocsFactoryService)
], imports: [RouterModule, UpgradedServicesModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpgradeModule, decorators: [{
type: NgModule,
args: [{
imports: [RouterModule, UpgradedServicesModule],
exports: [],
providers: [
absoluteDateServiceProvider,
bridgeServiceProvider,
authBridgeServiceProvider,
smartRulesServiceProvider,
hookNavigator(Ng1NodesFactoryService),
hookTab(Ng1TabsFactoryService),
hookActionBar(Ng1ActionBarFactoryService),
hookAction(Ng1ActionFactoryService),
hookBreadcrumb(Ng1BreadcrumbFactoryService),
hookDocs(Ng1DocsFactoryService)
]
}]
}] });
function c8yAlertDecorator($delegate, $rootScope, $injector) {
'ngInject';
$delegate.add = alert => {
$delegate.addAlert(transformAlert(alert));
};
$rootScope.$on('alert', (evt, alert) => {
$delegate.addAlert(transformAlert(alert));
});
$rootScope.$on('message', (evt, alert) => {
$delegate.addAlert(transformAlert(alert));
});
/**
* Solution based on the: https://stackoverflow.com/questions/40102148/how-to-iterate-over-all-properties-in-objects-prototype-chain.
* Problem came after switching to ES6, as all prototype properties of classes are non-enumerable.
*/
const allNames = new Set();
for (let o = $delegate; o !== Object.prototype; o = Object.getPrototypeOf(o)) {
for (const name of Object.getOwnPropertyNames(o)) {
allNames.add(name);
}
}
Array.from(allNames).forEach((property) => {
if (typeof $delegate[property] === 'function') {
$delegate[property] = $delegate[property].bind($delegate);
}
});
function transformAlert(alert) {
const newAlert = { ...alert };
if (alert.onClose) {
newAlert.onClose = () => {
$injector.invoke(alert.onClose);
};
}
if (alert.onDetail) {
newAlert.onDetail = () => {
$injector.invoke(alert.onDetail);
};
}
return newAlert;
}
return $delegate;
}
const bootstrapComponentDowngradedComponent = downgradeComponent({
component: BootstrapComponent
});
const userTotpComponentDowngradedComponent = downgradeComponent({
component: UserTotpRevokeComponent
});
const appLogsAutoRefreshComponentDowngradedComponent = downgradeComponent({
component: AppLogsAutoRefreshComponent
});
const dataGridComponentDowngradedComponent = downgradeComponent({
component: DataGridComponent
});
const loadingComponentDowngradedComponent = downgradeComponent({
component: LoadingComponent
});
const rangeDisplayComponentDowngradedComponent = downgradeComponent({
component: RangeDisplayComponent
});
const helpComponentDowngradedComponent = downgradeComponent({ component: HelpComponent });
const highlightComponentDowngradedComponent = downgradeComponent({
component: HighlightComponent,
inputs: ['pattern', 'text']
});
const emptyStateComponentDowngradedComponent = downgradeComponent({
component: EmptyStateComponent
});
const datapointSelectionListComponentDowngradedComponent = downgradeComponent({
component: DatapointSelectionListComponent
});
const paginationComponentDowngradedComponent = downgradeComponent({
component: PaginationComponent
});
const rolesAssetTreeComponentDowngradedComponent = downgradeComponent({
component: RolesAssetTreeComponent
});
const passwordInputComponentDowngradedComponent = downgradeComponent({
component: PasswordInputComponent
});
const platformConfigurationFormDowngradedComponent = downgradeComponent({
component: PlatformConfigurationFormComponent
});
const widgetPreviewWrapperDowngradedComponent = downgradeComponent({
component: WidgetPreviewWrapperComponent
});
class ServerMessagesService {
constructor(translateService, patterns) {
this.translateService = translateService;
this.MESSAGE_PATTERNS = patterns;
}
translate(s) {
return this.translateService.instant(s);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ServerMessagesService, deps: [{ token: i1.TranslateService }, { token: HOOK_PATTERN_MESSAGES }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ServerMessagesService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ServerMessagesService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.TranslateService }, { type: undefined, decorators: [{
type: Inject,
args: [HOOK_PATTERN_MESSAGES]
}] }] });
const absoluteDateServiceDowngradedInjectable = downgradeInjectable(AbsoluteDateService);
const bridgeServiceDowngradedInjectable = downgradeInjectable(BridgeService);
const authBridgeServiceDowngradedInjectable = downgradeInjectable(AuthBridgeService);
const appStateServiceDowngradedInjectable = downgradeInjectable(AppStateService);
const headerServiceDowngradedInjectable = downgradeInjectable(HeaderService);
const alertsServiceDowngradedInjectable = downgradeInjectable(AlertService);
const userMenuServiceDowngradedInjectable = downgradeInjectable(UserMenuService);
const apiServiceDowngradedInjectable = downgradeInjectable(ApiService);
const docsServiceDowngradedInjectable = downgradeInjectable(DocsService);
const passwordServiceDowngradedInjectable = downgradeInjectable(PasswordService);
const translateServiceDowngradedInjectable = downgradeInjectable(TranslateService);
const cachedLocaleDictionaryServiceDowngradedInjectable = downgradeInjectable(CachedLocaleDictionaryService);
const globalConfigServiceDowngradedInjectable = downgradeInjectable(GlobalConfigService);
const serverMessagesServiceDowngradedInjectable = downgradeInjectable(ServerMessagesService);
const modalServiceDowngradedInjectable = downgradeInjectable(ModalService);
const gainsightServiceDowngradedInjectable = downgradeInjectable(GainsightService);
const filesServiceDowngradedInjectable = downgradeInjectable(FilesService);
const deviceTypeDetailEditedServiceDowngradedInjectable = downgradeInjectable(DeviceTypeDetailEditedService);
const deviceGridServiceDowngradedInjectable = downgradeInjectable(DeviceGridService);
const serviceRegistryInjectable = downgradeInjectable(ServiceRegistry);
const assetLinkPipeDowngradedInjectable = downgradeInjectable(AssetLinkPipe);
const propertyValueTransformServiceDowngradedInjectable = downgradeInjectable(PropertyValueTransformService);
const featureCacheServiceDowngradedInjectable = downgradeInjectable(FeatureCacheService);
const datapointSelectorServiceDowngradedInjectable = downgradeInjectable(DatapointSelectorService);
const dateFormatServiceInjectable = downgradeInjectable(DateFormatService);
function gettextCatalogDecorator($delegate, $interpolate, c8yTranslate) {
'ngInject';
const gettextCatalog = $delegate;
const originalGetString = angular.bind(gettextCatalog, gettextCatalog.getString);
function newGetString(input, scope, context) {
if (typeof input === 'string') {
const translatedString = originalGetString(input, scope, context);
const interpolatedString = scope ? $interpolate(input)(scope) : input;
let stringToReturn = translatedString;
if (translatedString && translatedString === interpolatedString) {
const translatedServerMessage = c8yTranslate.instant(interpolatedString);
stringToReturn = translatedServerMessage;
}
return stringToReturn;
}
return input;
}
gettextCatalog.getString = newGetString;
return gettextCatalog;
}
function groupTypesHierarchyNavigatorDecorator($delegate, $q) {
'ngInject';
$delegate.loadAll = () => $q.when();
$delegate.addGroupNavigation = () => $q.when();
return $delegate;
}
function c8yNg1HttpInterceptor($q, c8yLoadingIndicator, c8yApiService) {
'ngInject';
function request(config) {
const { url, method } = config;
c8yApiService.onStart({ url, method, options: config });
return config;
}
function requestError(rejection) {
finishRequest(rejection);
return $q.reject(rejection);
}
function response(res) {
finishRequest(res);
return res;
}
function responseError(rejection) {
finishRequest(rejection);
c8yLoadingIndicator.responseError(rejection);
return $q.reject(rejection);
}
function finishRequest(res) {
const { url, method } = res.config;
c8yApiService.onFinish({
url,
method,
response: res,
options: res.config
});
}
return {
request,
requestError,
response,
responseError
};
}
class NavigatorNodeRootLegacy extends NavigatorNodeRoot {
addRoot(nodeData) {
let duplicate;
if (nodeData.path === '') {
nodeData.path = '/';
}
nodeData.label = nodeData.name;
if (typeof nodeData.parent === 'object') {
nodeData.parent.label = nodeData.parent.name;
}
if (nodeData.preventDuplicates) {
duplicate = this.find(({ path, parents, label }) => {
return (path === nodeData.path &&
label === nodeData.label &&
parents.some(p => p.label === nodeData.parent));
});
if (duplicate) {
duplicate.routerLinkExact = false;
}
}
return duplicate || super.addRoot(nodeData);
}
createNode(node) {
const newNode = super.createNode(node);
const update = newNode.update.bind(newNode);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const root = this;
return Object.defineProperties(assign(newNode, {
realName: newNode.name || newNode.label,
_parent: true, // just use it to detect if it has been deleted
update(data) {
if (this._parent === undefined) {
// _parent was deleted somene instead to put this in root
root.addRoot(this);
// put it back so it can be deleted again
this._parent = true;
}
update(data);
},
addChild(nodeChild) {
this.add(root.createNode(nodeChild));
}
}), {
label: {
get() {
return this.realName || '';
},
set(name) {
this.realName = name;
}
},
name: {
get() {
return this.realName || '';
},
set(name) {
this.realName = name;
}
},
show: {
get() {
return !this.hidden;
},
set(show) {
this.hidden = !show;
},
configurable: true
}
});
}
}
// Just to hook into the bridge service
function c8yNavigatorProvider() {
const root = new NavigatorNodeRootLegacy();
const rootNodesSubject = new Subject();
const conditionalNodes = [];
const rootNodes$ = rootNodesSubject.pipe(merge$1(defer(() => of(root.children))));
function addNavigation(nodes) {
const nodeList = Array.isArray(nodes) ? nodes : [nodes];
nodeList.forEach(node => {
if (isConditional(node)) {
node.hidden = undefined;
conditionalNodes.push(node);
}
node.navNode = root.addRoot(node);
});
rootNodesSubject.next(root.children);
}
function removeNavigation(node) {
const found = root.find(n => n === node);
if (found) {
found.parents.forEach(p => p.remove(found));
rootNodesSubject.next(root.children);
}
}
function findNode(node) {
return root.find(node);
}
function isConditional(node) {
return node.showIf || node.showIfPermissions || node.showIfContainsVisibleViews;
}
function $get($q, $injector) {
'ngInject';
// This avoids the circular dependency
setTimeout(() => conditionalNodes.forEach(processShowIf));
function processShowIf(node) {
const c8yUiUtil = $injector.get('c8yUiUtil');
const visibilityPromises = [];
const { showIf, showIfPermissions, showIfContainsVisibleViews } = node;
if (showIf) {
visibilityPromises.push($injector.invoke(showIf));
}
if (showIfContainsVisibleViews) {
visibilityPromises.push(viewsConditionalVisibility(node));
}
c8yUiUtil
.configureVisibility({
showIf: () => $q.all(visibilityPromises).then(every),
showIfPermissions
}, 'visible')
.then(({ visible }) => {
if (visible) {
node.navNode.update({
hidden: false,
showIf: null,
showIfPermission: null,
showIfContainsVisibleViews: null
});
}
else {
node.navNode.update({
hidden: true
});
}
});
}
function viewsConditionalVisibility(node) {
const c8yUiUtil = $injector.get('c8yUiUtil');
const c8yViews = $injector.get('c8yViews');
const views = c8yViews.getByPath(node.path);
return $q
.all(map(views, view => c8yUiUtil
.configureVisibility(pick(view, ['showIf', 'showIfPermissions']), 'show', false)
.then(property('show'))))
.then(some);
}
return {
rootNodes() {
return root.children;
},
findNode,
addNavigation,
removeNavigation,
rootNodes$
};
}
return {
$get,
addNavigation,
removeNavigation
};
}
const rootComponent = {
template: `
<c8y-bootstrap>
<div id="c8y-legacy-view">
<div ng-view ng-if="vm.widthSet && vm.authState.hasAuth"></div>
</div>
</c8y-bootstrap>`,
controller: c8yUiRootController,
controllerAs: 'vm'
};
function c8yUiRootController($rootScope, $timeout, c8yBase, c8yNavigator, c8yApplication, c8yHeaderService) {
'ngInject';
// eslint-disable-next-line @typescript-eslint/no-this-alias
const vm = this;
Object.assign(vm, {
$onInit,
navOpen: false
});
////////////
function $onInit() {
c8yHeaderService
.map(states => states.nav.open)
.subscribe(isOpen => {
vm.navOpen = isOpen;
});
c8yHeaderService.configNavigator({ canToggle: true });
$rootScope.$on('authStateChange', onAuthStateChange);
vm.rootNodes = c8yNavigator.rootNodes;
c8yApplication.currentAppCached().then(onAppInfo);
vm.navHiddenOnStartup = c8yBase.appOption('hide_navigator');
checkReady();
}
function onAuthStateChange(evt, data) {
vm.authState = data;
}
function onAppInfo() {
vm.tabsHorizontal = c8yBase.appOption('tabsHorizontal');
}
function checkReady() {
const element = document.querySelector('#c8y-legacy-view');
const hasWidth = element && element.clientWidth;
if (hasWidth) {
vm.widthSet = true;
}