@c8y/ngx-components 1023.97.3 → 1023.97.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/alarms/index.d.ts.map +1 -1
- package/context-dashboard/index.d.ts +29 -3
- package/context-dashboard/index.d.ts.map +1 -1
- package/ecosystem/index.d.ts.map +1 -1
- package/fesm2022/c8y-ngx-components-alarms.mjs +10 -7
- package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-asset-add.mjs +2 -2
- package/fesm2022/c8y-ngx-components-context-dashboard-asset-add.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-asset-view.mjs +2 -2
- package/fesm2022/c8y-ngx-components-context-dashboard-asset-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-cockpit-home-dashboard.mjs +3 -3
- package/fesm2022/c8y-ngx-components-context-dashboard-cockpit-home-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-device-add.mjs +2 -2
- package/fesm2022/c8y-ngx-components-context-dashboard-device-add.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs +2 -2
- package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs +2 -2
- package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs +142 -19
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs +6 -7
- package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-report-dashboard.mjs +4 -4
- package/fesm2022/c8y-ngx-components-report-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-upgrade.mjs +40 -8
- package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +12 -5
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs +40 -11
- package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-three-d-rotation.mjs +19 -0
- package/fesm2022/c8y-ngx-components-widgets-implementations-three-d-rotation.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +229 -31
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/index.d.ts +83 -7
- package/index.d.ts.map +1 -1
- package/locales/de.po +3 -0
- package/locales/es.po +3 -0
- package/locales/fr.po +3 -0
- package/locales/ja_JP.po +3 -0
- package/locales/ko.po +3 -0
- package/locales/locales.pot +3 -0
- package/locales/nl.po +3 -0
- package/locales/pl.po +3 -0
- package/locales/pt_BR.po +3 -0
- package/locales/zh_CN.po +3 -0
- package/locales/zh_TW.po +3 -0
- package/package.json +1 -1
- package/upgrade/index.d.ts +8 -0
- package/upgrade/index.d.ts.map +1 -1
- package/widgets/implementations/asset-table/index.d.ts.map +1 -1
- package/widgets/implementations/quick-links/index.d.ts +3 -1
- package/widgets/implementations/quick-links/index.d.ts.map +1 -1
- package/widgets/implementations/three-d-rotation/index.d.ts.map +1 -1
|
@@ -12833,7 +12833,12 @@ class HeaderService extends StateService {
|
|
|
12833
12833
|
* Delay of 300ms is intended for animation purpose.
|
|
12834
12834
|
*/
|
|
12835
12835
|
verifyIfNavOpen() {
|
|
12836
|
-
|
|
12836
|
+
// Drop any previous subscription before re-subscribing so repeated calls (e.g. a re-initialised
|
|
12837
|
+
// header bar) do not accumulate never-completing subscriptions on the long-lived
|
|
12838
|
+
// canToggleNavigator$. The subscription is kept open intentionally so it still reacts when nodes
|
|
12839
|
+
// are added later (per this method's contract).
|
|
12840
|
+
this.navOpenSubscription?.unsubscribe();
|
|
12841
|
+
this.navOpenSubscription = this.canToggleNavigator$
|
|
12837
12842
|
.pipe(debounceTime(300))
|
|
12838
12843
|
.subscribe(hasItems => hasItems && this.shouldToggle && this.toggleNavigator());
|
|
12839
12844
|
}
|
|
@@ -14288,31 +14293,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
14288
14293
|
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$4.Router }, { type: PluginsResolveService }] });
|
|
14289
14294
|
|
|
14290
14295
|
class TitleOutletComponent {
|
|
14291
|
-
constructor(headerService, element, zone) {
|
|
14296
|
+
constructor(headerService, element, zone, destroyRef) {
|
|
14292
14297
|
this.headerService = headerService;
|
|
14293
14298
|
this.element = element;
|
|
14294
14299
|
this.zone = zone;
|
|
14300
|
+
this.destroyRef = destroyRef;
|
|
14295
14301
|
this.title = undefined;
|
|
14296
14302
|
this.pageTitleUpdate = true;
|
|
14303
|
+
// These subscribe to the root-singleton HeaderService (a never-completing BehaviorSubject), so
|
|
14304
|
+
// without takeUntilDestroyed the observers — which capture this component (and, for the last one,
|
|
14305
|
+
// its host element) — would stay registered on the app-lifetime singleton and leak the destroyed
|
|
14306
|
+
// outlet and its detached DOM.
|
|
14297
14307
|
const title$ = this.headerService.map(state => state.title);
|
|
14298
|
-
title$.subscribe(title => {
|
|
14308
|
+
title$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(title => {
|
|
14299
14309
|
this.title = title;
|
|
14300
14310
|
});
|
|
14301
14311
|
const pageTitleUpdate$ = this.headerService.map(state => state.pageTitleUpdate);
|
|
14302
|
-
pageTitleUpdate
|
|
14312
|
+
pageTitleUpdate$
|
|
14313
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
14314
|
+
.subscribe(pageTitleUpdate => (this.pageTitleUpdate = pageTitleUpdate));
|
|
14303
14315
|
this.zone.runOutsideAngular(() => {
|
|
14304
14316
|
this.headerService.state$
|
|
14305
|
-
.pipe(debounceTime(100), filter(state => state.pageTitleUpdate), debounceTime(100), map(() => this.element.nativeElement.querySelector('h1')), filter(el => el !== null), map(el => el.innerText), filter(Boolean))
|
|
14317
|
+
.pipe(debounceTime(100), filter(state => state.pageTitleUpdate), debounceTime(100), map(() => this.element.nativeElement.querySelector('h1')), filter(el => el !== null), map(el => el.innerText), filter(Boolean), takeUntilDestroyed(this.destroyRef))
|
|
14306
14318
|
.subscribe((title) => headerService.changePageTitle(title));
|
|
14307
14319
|
});
|
|
14308
14320
|
}
|
|
14309
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: TitleOutletComponent, deps: [{ token: HeaderService }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14321
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: TitleOutletComponent, deps: [{ token: HeaderService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14310
14322
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: TitleOutletComponent, isStandalone: true, selector: "c8y-title-outlet", ngImport: i0, template: "<div class=\"c8y-ui-title\" data-cy=\"c8y-title--title-outlet\">\n <div class=\"title\" *c8yOutlet=\"title\"></div>\n</div>\n", dependencies: [{ kind: "directive", type: OutletDirective, selector: "[c8yOutlet]", inputs: ["c8yOutlet", "c8yOutletProperties", "c8yOutletInjector"] }] }); }
|
|
14311
14323
|
}
|
|
14312
14324
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: TitleOutletComponent, decorators: [{
|
|
14313
14325
|
type: Component,
|
|
14314
14326
|
args: [{ selector: 'c8y-title-outlet', standalone: true, imports: [OutletDirective], template: "<div class=\"c8y-ui-title\" data-cy=\"c8y-title--title-outlet\">\n <div class=\"title\" *c8yOutlet=\"title\"></div>\n</div>\n" }]
|
|
14315
|
-
}], ctorParameters: () => [{ type: HeaderService }, { type: i0.ElementRef }, { type: i0.NgZone }] });
|
|
14327
|
+
}], ctorParameters: () => [{ type: HeaderService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.DestroyRef }] });
|
|
14316
14328
|
|
|
14317
14329
|
class BreadcrumbOutletComponent {
|
|
14318
14330
|
constructor() {
|
|
@@ -16138,7 +16150,8 @@ class NavigatorNodeComponent {
|
|
|
16138
16150
|
this.nodeInit$.next();
|
|
16139
16151
|
});
|
|
16140
16152
|
}
|
|
16141
|
-
this.
|
|
16153
|
+
this.refreshCallbackRef = this.updateIcon.bind(this);
|
|
16154
|
+
this.node.refreshCallback = this.refreshCallbackRef;
|
|
16142
16155
|
}
|
|
16143
16156
|
/**
|
|
16144
16157
|
* Returns the expander title.
|
|
@@ -16192,6 +16205,16 @@ class NavigatorNodeComponent {
|
|
|
16192
16205
|
ngOnDestroy() {
|
|
16193
16206
|
clearTimeout(this.viewInitTimeout);
|
|
16194
16207
|
if (this.node) {
|
|
16208
|
+
// The navigator node is long-lived (re-emitted from NavigatorService.items$), so the
|
|
16209
|
+
// back-references this component stored on it must be cleared or they retain the destroyed
|
|
16210
|
+
// component, its PopoverConfirm child and its icon view subtree. Guard by identity so a newer
|
|
16211
|
+
// component for the same persistent node is not clobbered.
|
|
16212
|
+
if (this.node.refreshCallback === this.refreshCallbackRef) {
|
|
16213
|
+
this.node.refreshCallback = undefined;
|
|
16214
|
+
}
|
|
16215
|
+
if (this.node.confirm === this.confirm) {
|
|
16216
|
+
this.node.confirm = undefined;
|
|
16217
|
+
}
|
|
16195
16218
|
this.node.destroy();
|
|
16196
16219
|
}
|
|
16197
16220
|
}
|
|
@@ -29338,6 +29361,15 @@ class DynamicComponentComponent {
|
|
|
29338
29361
|
this.expandErrorDetails = false;
|
|
29339
29362
|
this.dynamicComponentErrorStrategy = DynamicComponentErrorStrategy;
|
|
29340
29363
|
this.destroy$ = new Subject();
|
|
29364
|
+
/**
|
|
29365
|
+
* `ngOnChanges` is async (it awaits the component lookup, lazy chunk loading and resolvers), so a
|
|
29366
|
+
* navigation can destroy this host while a (re-)creation is still in flight. Creating the widget
|
|
29367
|
+
* after destroy would insert it into the destroyed `ViewContainerRef` — such a view is never
|
|
29368
|
+
* destroyed and permanently retains the whole detached dashboard DOM (Angular keeps every live
|
|
29369
|
+
* view in an internal registry until it is destroyed). This flag lets the pending async work
|
|
29370
|
+
* bail out instead.
|
|
29371
|
+
*/
|
|
29372
|
+
this.isDestroyed = false;
|
|
29341
29373
|
}
|
|
29342
29374
|
/**
|
|
29343
29375
|
* Calls the dynamic component life cycle hook. Currently only
|
|
@@ -29352,6 +29384,9 @@ class DynamicComponentComponent {
|
|
|
29352
29384
|
*/
|
|
29353
29385
|
async ngOnChanges(changes) {
|
|
29354
29386
|
const cmp = await this.dynamicComponentService.getById(this.componentId);
|
|
29387
|
+
if (this.isDestroyed) {
|
|
29388
|
+
return;
|
|
29389
|
+
}
|
|
29355
29390
|
let errors = new Array();
|
|
29356
29391
|
if (cmp) {
|
|
29357
29392
|
this.errorStrategy = cmp.errorStrategy || DynamicComponentErrorStrategy.CUSTOM;
|
|
@@ -29359,6 +29394,9 @@ class DynamicComponentComponent {
|
|
|
29359
29394
|
const [resolvedConfig] = await this.dynamicComponentService.executeResolvers([
|
|
29360
29395
|
{ componentId: this.componentId, config: this.config }
|
|
29361
29396
|
]);
|
|
29397
|
+
if (this.isDestroyed) {
|
|
29398
|
+
return;
|
|
29399
|
+
}
|
|
29362
29400
|
Object.entries(resolvedConfig).forEach(([key, value]) => set(this.config, key, value));
|
|
29363
29401
|
}
|
|
29364
29402
|
const resolvedValuesOfConfiguration = cmp.resolve
|
|
@@ -29391,8 +29429,17 @@ class DynamicComponentComponent {
|
|
|
29391
29429
|
this.emitChangeOnComponent({ config: new SimpleChange(oldConfig, this.config, false) });
|
|
29392
29430
|
}
|
|
29393
29431
|
ngOnDestroy() {
|
|
29432
|
+
this.isDestroyed = true;
|
|
29394
29433
|
this.destroy$.next();
|
|
29395
29434
|
this.destroy$.complete();
|
|
29435
|
+
// Release references to the dynamically created widget. The ViewContainerRef destroys the
|
|
29436
|
+
// created component automatically, but the host keeps strong fields pointing at the widget
|
|
29437
|
+
// instance (and, via its config/alerts, at large object graphs). If anything still references
|
|
29438
|
+
// this now-destroyed host, those fields would keep the whole widget — and its detached DOM —
|
|
29439
|
+
// alive. Clearing them breaks that retention edge.
|
|
29440
|
+
this.componentRef = undefined;
|
|
29441
|
+
this.componentInstance = undefined;
|
|
29442
|
+
this.error = undefined;
|
|
29396
29443
|
}
|
|
29397
29444
|
emitChangeOnComponent(changes) {
|
|
29398
29445
|
const ngOnChanges = this.componentRef?.instance?.ngOnChanges;
|
|
@@ -29404,6 +29451,12 @@ class DynamicComponentComponent {
|
|
|
29404
29451
|
try {
|
|
29405
29452
|
this.error = undefined;
|
|
29406
29453
|
const componentType = await this.getComponentType(dynamicComponent);
|
|
29454
|
+
// The lazy-component await above (and the awaits in ngOnChanges) can outlive this host:
|
|
29455
|
+
// creating the widget into the destroyed ViewContainerRef would leak it — and the whole
|
|
29456
|
+
// detached dashboard DOM it references — until a full page reload.
|
|
29457
|
+
if (this.isDestroyed) {
|
|
29458
|
+
return;
|
|
29459
|
+
}
|
|
29407
29460
|
this.host.clear();
|
|
29408
29461
|
this.componentRef = this.host.createComponent(componentType, {
|
|
29409
29462
|
environmentInjector: (dynamicComponent.injector || this.injector)
|
|
@@ -29477,19 +29530,18 @@ class DynamicComponentComponent {
|
|
|
29477
29530
|
return of(true);
|
|
29478
29531
|
}
|
|
29479
29532
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DynamicComponentComponent, deps: [{ token: DynamicComponentService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29480
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
29533
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: DynamicComponentComponent, isStandalone: true, selector: "c8y-dynamic-component", inputs: { componentId: "componentId", config: "config", mode: "mode", notFoundError: "notFoundError", executeResolvers: "executeResolvers" }, outputs: { updateWidgetClasses: "updateWidgetClasses" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["host"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #host></ng-template>\n\n@if (error && notFoundError) {\n <div\n class=\"alert alert-warning m-8\"\n role=\"alert\"\n >\n <strong class=\"message\">\n {{\n 'This widget cannot be rendered because the current application does not support the following component:'\n | translate\n }}\n {{ componentId }}.\n </strong>\n <p class=\"text-muted m-t-8\">\n <button\n class=\"btn btn-clean\"\n (click)=\"expandErrorDetails = !expandErrorDetails\"\n >\n <i c8yIcon=\"chevron-down\"></i>\n @if (!expandErrorDetails) {\n <span translate>Show details</span>\n } @else {\n <span translate>Hide details</span>\n }\n </button>\n </p>\n <div\n [collapse]=\"!expandErrorDetails\"\n [isAnimated]=\"true\"\n >\n <pre>\n {{ error }}\n </pre\n >\n </div>\n </div>\n}\n\n@if (\n errorStrategy === dynamicComponentErrorStrategy.OVERLAY_ERROR &&\n componentInstance?.alerts?.anyAlertExists$ | async\n) {\n <div class=\"overlay-center-vertically d-flex d-col a-i-stretch j-c-start p-16 p-r-24 p-l-24\">\n <c8y-dynamic-component-alerts\n [alerts]=\"componentInstance.alerts\"\n ></c8y-dynamic-component-alerts>\n </div>\n}\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i2$2.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "component", type: DynamicComponentAlertsComponent, selector: "c8y-dynamic-component-alerts", inputs: ["alerts"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
29481
29534
|
}
|
|
29482
29535
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DynamicComponentComponent, decorators: [{
|
|
29483
29536
|
type: Component,
|
|
29484
29537
|
args: [{ selector: 'c8y-dynamic-component', standalone: true, imports: [
|
|
29485
|
-
NgIf,
|
|
29486
29538
|
IconDirective,
|
|
29487
29539
|
C8yTranslateDirective,
|
|
29488
29540
|
CollapseModule,
|
|
29489
29541
|
DynamicComponentAlertsComponent,
|
|
29490
29542
|
C8yTranslatePipe,
|
|
29491
29543
|
AsyncPipe
|
|
29492
|
-
], template: "<ng-template #host></ng-template>\n\n<div
|
|
29544
|
+
], template: "<ng-template #host></ng-template>\n\n@if (error && notFoundError) {\n <div\n class=\"alert alert-warning m-8\"\n role=\"alert\"\n >\n <strong class=\"message\">\n {{\n 'This widget cannot be rendered because the current application does not support the following component:'\n | translate\n }}\n {{ componentId }}.\n </strong>\n <p class=\"text-muted m-t-8\">\n <button\n class=\"btn btn-clean\"\n (click)=\"expandErrorDetails = !expandErrorDetails\"\n >\n <i c8yIcon=\"chevron-down\"></i>\n @if (!expandErrorDetails) {\n <span translate>Show details</span>\n } @else {\n <span translate>Hide details</span>\n }\n </button>\n </p>\n <div\n [collapse]=\"!expandErrorDetails\"\n [isAnimated]=\"true\"\n >\n <pre>\n {{ error }}\n </pre\n >\n </div>\n </div>\n}\n\n@if (\n errorStrategy === dynamicComponentErrorStrategy.OVERLAY_ERROR &&\n componentInstance?.alerts?.anyAlertExists$ | async\n) {\n <div class=\"overlay-center-vertically d-flex d-col a-i-stretch j-c-start p-16 p-r-24 p-l-24\">\n <c8y-dynamic-component-alerts\n [alerts]=\"componentInstance.alerts\"\n ></c8y-dynamic-component-alerts>\n </div>\n}\n" }]
|
|
29493
29545
|
}], ctorParameters: () => [{ type: DynamicComponentService }, { type: i0.Injector }], propDecorators: { componentId: [{
|
|
29494
29546
|
type: Input
|
|
29495
29547
|
}], config: [{
|
|
@@ -30180,6 +30232,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
30180
30232
|
* ```
|
|
30181
30233
|
*/
|
|
30182
30234
|
class DashboardChildComponent {
|
|
30235
|
+
static { this.WIDGET_THEME_FOUNDATION_MAP = {
|
|
30236
|
+
'panel-content-dark': 'c8y-dark-theme',
|
|
30237
|
+
'panel-content-white': 'c8y-light-theme'
|
|
30238
|
+
}; }
|
|
30239
|
+
static { this.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY = 768; }
|
|
30240
|
+
/**
|
|
30241
|
+
* Emits true in one-column (mobile) view. SHARED across all instances via a single static
|
|
30242
|
+
* `window 'resize'` subscription — previously every widget card created its own listener +
|
|
30243
|
+
* debounce timer (N per dashboard), wasteful on dashboards with many widgets. One listener now
|
|
30244
|
+
* serves them all (refCount:false keeps it warm for the app's lifetime).
|
|
30245
|
+
*/
|
|
30246
|
+
static { this.oneColumnView$ = fromEvent(window, 'resize').pipe(debounceTime(200), map(() => document.documentElement.clientWidth <=
|
|
30247
|
+
DashboardChildComponent.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY), startWith(document.documentElement.clientWidth <=
|
|
30248
|
+
DashboardChildComponent.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: false })); }
|
|
30183
30249
|
set templateActions(actions) {
|
|
30184
30250
|
this.addActions(actions, true);
|
|
30185
30251
|
}
|
|
@@ -30231,7 +30297,6 @@ class DashboardChildComponent {
|
|
|
30231
30297
|
this._pxWidth = '100%';
|
|
30232
30298
|
this._pxHeight = '100%';
|
|
30233
30299
|
this.fullscreen = false;
|
|
30234
|
-
this.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY = 768;
|
|
30235
30300
|
/**
|
|
30236
30301
|
* The width of the component in grid-columns.
|
|
30237
30302
|
*/
|
|
@@ -30270,12 +30335,8 @@ class DashboardChildComponent {
|
|
|
30270
30335
|
* All classes added to this child
|
|
30271
30336
|
*/
|
|
30272
30337
|
this.class = {};
|
|
30273
|
-
/**
|
|
30274
|
-
|
|
30275
|
-
*/
|
|
30276
|
-
this.isOneColumnView$ = fromEvent(window, 'resize').pipe(map(_ => {
|
|
30277
|
-
return (document.documentElement.clientWidth <= this.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY);
|
|
30278
|
-
}), debounceTime(200), startWith(document.documentElement.clientWidth <= this.MD_BOOTSTRAP_BREAKPOINT_READONLY_CLASS_PROPERTY));
|
|
30338
|
+
/** Triggers on resize and returns true if in one column view (mobile view). */
|
|
30339
|
+
this.isOneColumnView$ = DashboardChildComponent.oneColumnView$;
|
|
30279
30340
|
/**
|
|
30280
30341
|
* An indicator if the child is intersected (that mean visible for the user)
|
|
30281
30342
|
*/
|
|
@@ -30286,11 +30347,21 @@ class DashboardChildComponent {
|
|
|
30286
30347
|
this.lastChange = null;
|
|
30287
30348
|
}
|
|
30288
30349
|
ngOnChanges() {
|
|
30350
|
+
const classObj = Array.isArray(this.class)
|
|
30351
|
+
? this.class.reduce((acc, cls) => ({ ...acc, [cls]: true }), {})
|
|
30352
|
+
: (this.class ?? {});
|
|
30353
|
+
const foundationClasses = {};
|
|
30354
|
+
for (const [contentClass, foundationClass] of Object.entries(DashboardChildComponent.WIDGET_THEME_FOUNDATION_MAP)) {
|
|
30355
|
+
if (classObj[contentClass]) {
|
|
30356
|
+
foundationClasses[foundationClass] = true;
|
|
30357
|
+
}
|
|
30358
|
+
}
|
|
30289
30359
|
this.klasses = {
|
|
30290
30360
|
card: true,
|
|
30291
30361
|
'card-dashboard': true,
|
|
30292
30362
|
'on-resize': this.isResize,
|
|
30293
|
-
...
|
|
30363
|
+
...foundationClasses,
|
|
30364
|
+
...classObj
|
|
30294
30365
|
};
|
|
30295
30366
|
}
|
|
30296
30367
|
ngOnInit() {
|
|
@@ -30298,8 +30369,7 @@ class DashboardChildComponent {
|
|
|
30298
30369
|
setTimeout(() => this.setDynamicDimension());
|
|
30299
30370
|
}
|
|
30300
30371
|
if (this.useIntersection && 'IntersectionObserver' in window) {
|
|
30301
|
-
|
|
30302
|
-
intersectionObserver.observe(this.element.nativeElement);
|
|
30372
|
+
this.observeIntersection();
|
|
30303
30373
|
}
|
|
30304
30374
|
else {
|
|
30305
30375
|
this.intersected = true;
|
|
@@ -30352,6 +30422,9 @@ class DashboardChildComponent {
|
|
|
30352
30422
|
if (this.changeSubscription) {
|
|
30353
30423
|
this.changeSubscription.unsubscribe();
|
|
30354
30424
|
}
|
|
30425
|
+
// Disconnect the IntersectionObserver so it stops retaining this (now detached) card element.
|
|
30426
|
+
this.intersectionObserver?.disconnect();
|
|
30427
|
+
this.intersectionObserver = undefined;
|
|
30355
30428
|
this._additionalHeaderTemplates.complete();
|
|
30356
30429
|
this.removeSelfFromDashboard();
|
|
30357
30430
|
}
|
|
@@ -30363,6 +30436,20 @@ class DashboardChildComponent {
|
|
|
30363
30436
|
this.actions = [...this.actions, ...actions];
|
|
30364
30437
|
}
|
|
30365
30438
|
}
|
|
30439
|
+
/**
|
|
30440
|
+
* Re-arms intersection tracking after a card was restored following a cancelled navigation. The
|
|
30441
|
+
* observer one-shot-unobserves on first intersection, so once a card has been shown and then
|
|
30442
|
+
* blanked it would no longer be watched; this lets the dashboard put it back under observation.
|
|
30443
|
+
*/
|
|
30444
|
+
reobserve() {
|
|
30445
|
+
if (this.useIntersection && 'IntersectionObserver' in window) {
|
|
30446
|
+
this.intersectionObserver?.disconnect();
|
|
30447
|
+
this.observeIntersection();
|
|
30448
|
+
}
|
|
30449
|
+
else {
|
|
30450
|
+
this.intersected = true;
|
|
30451
|
+
}
|
|
30452
|
+
}
|
|
30366
30453
|
removeSelfFromDashboard() {
|
|
30367
30454
|
const i = this.dashboard.children.indexOf(this);
|
|
30368
30455
|
if (i >= 0) {
|
|
@@ -30375,6 +30462,10 @@ class DashboardChildComponent {
|
|
|
30375
30462
|
getOrder() {
|
|
30376
30463
|
return `${Math.round((this.y + (this.x + 1) / 100) * 100)}`;
|
|
30377
30464
|
}
|
|
30465
|
+
observeIntersection() {
|
|
30466
|
+
this.intersectionObserver = new IntersectionObserver(events => (this.intersected = this.childInView(events, this.intersectionObserver)));
|
|
30467
|
+
this.intersectionObserver.observe(this.element.nativeElement);
|
|
30468
|
+
}
|
|
30378
30469
|
childInView(events, observer) {
|
|
30379
30470
|
const intersectingEvent = events.find(event => event.isIntersecting);
|
|
30380
30471
|
if (intersectingEvent) {
|
|
@@ -32016,6 +32107,16 @@ class WidgetAutoRefreshContextComponent {
|
|
|
32016
32107
|
this.listenOnDashboardSaveOperation();
|
|
32017
32108
|
}
|
|
32018
32109
|
ngOnDestroy() {
|
|
32110
|
+
// Tear down THIS instance's subscriptions unconditionally. They are per-instance — each pipes
|
|
32111
|
+
// through takeUntil(this.destroy$) and its callback captures this component. Previously destroy$
|
|
32112
|
+
// was only completed when the shared globalRefreshWidgetsCount reached 0, so whenever another
|
|
32113
|
+
// auto-refresh context was still alive (count > 1 — e.g. the brief overlap while navigating
|
|
32114
|
+
// between dashboards, where the next context is created before this one is destroyed) the
|
|
32115
|
+
// destroyed instance's subscriptions to long-lived root streams (Router events, query params,
|
|
32116
|
+
// root BehaviorSubjects) stayed open and retained this component and its detached DOM. Only the
|
|
32117
|
+
// shared service reset must remain gated on the count.
|
|
32118
|
+
this.destroy$.next();
|
|
32119
|
+
this.destroy$.complete();
|
|
32019
32120
|
this.onContextDestroy();
|
|
32020
32121
|
}
|
|
32021
32122
|
onRefresh() {
|
|
@@ -32078,8 +32179,6 @@ class WidgetAutoRefreshContextComponent {
|
|
|
32078
32179
|
const widgetsCount = this.widgetGlobalAutoRefresh.globalRefreshWidgetsCount;
|
|
32079
32180
|
widgetsCount.update(count => count - 1);
|
|
32080
32181
|
if (widgetsCount() === 0) {
|
|
32081
|
-
this.destroy$.next();
|
|
32082
|
-
this.destroy$.complete();
|
|
32083
32182
|
this.widgetGlobalAutoRefresh.resetServiceToDefaults();
|
|
32084
32183
|
}
|
|
32085
32184
|
}
|
|
@@ -32089,7 +32188,7 @@ class WidgetAutoRefreshContextComponent {
|
|
|
32089
32188
|
.subscribe();
|
|
32090
32189
|
}
|
|
32091
32190
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: WidgetAutoRefreshContextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32092
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
32191
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: WidgetAutoRefreshContextComponent, isStandalone: true, selector: "c8y-widget-auto-refresh-context", inputs: { editMode$: "editMode$" }, ngImport: i0, template: "<c8y-action-bar-item\n [groupId]=\"ACTION_BAR_GROUP_ID\"\n [priority]=\"ACTION_BAR_PRIORITY\"\n [placement]=\"'left'\"\n>\n <form\n class=\"d-flex\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n [hidden]=\"editMode$ | async\"\n (loading)=\"globalRefreshWidgetLoading = $event\"\n formControlName=\"autoRefresh\"\n ></c8y-auto-refresh-control>\n\n <c8y-auto-refresh-select-control\n [hidden]=\"editMode$ | async\"\n formControlName=\"autoRefreshSeconds\"\n ></c8y-auto-refresh-select-control>\n </form>\n <div class=\"input-group-btn\">\n @if (!(editMode$ | async)) {\n <button\n class=\"btn btn-default\"\n style=\"border-left: 0\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"globalRefreshWidgetLoading\"\n (click)=\"onRefresh()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': globalRefreshWidgetLoading }\"\n ></i>\n </button>\n }\n </div>\n</c8y-action-bar-item>\n", dependencies: [{ kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$8.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$8.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", outputs: ["loading"] }, { kind: "component", type: AutoRefreshSelectControlComponent, selector: "c8y-auto-refresh-select-control" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
32093
32192
|
}
|
|
32094
32193
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: WidgetAutoRefreshContextComponent, decorators: [{
|
|
32095
32194
|
type: Component,
|
|
@@ -32099,13 +32198,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
32099
32198
|
ReactiveFormsModule,
|
|
32100
32199
|
AutoRefreshControlComponent,
|
|
32101
32200
|
AutoRefreshSelectControlComponent,
|
|
32102
|
-
NgIf,
|
|
32103
32201
|
TooltipModule,
|
|
32104
32202
|
IconDirective,
|
|
32105
32203
|
NgClass,
|
|
32106
32204
|
C8yTranslatePipe,
|
|
32107
32205
|
AsyncPipe
|
|
32108
|
-
], template: "<c8y-action-bar-item\n [groupId]=\"ACTION_BAR_GROUP_ID\"\n [priority]=\"ACTION_BAR_PRIORITY\"\n [placement]=\"'left'\"\n>\n <form\n class=\"d-flex\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n [hidden]=\"editMode$ | async\"\n (loading)=\"globalRefreshWidgetLoading = $event\"\n formControlName=\"autoRefresh\"\n ></c8y-auto-refresh-control>\n\n <c8y-auto-refresh-select-control\n [hidden]=\"editMode$ | async\"\n formControlName=\"autoRefreshSeconds\"\n ></c8y-auto-refresh-select-control>\n </form>\n <div class=\"input-group-btn\">\n <button\n
|
|
32206
|
+
], template: "<c8y-action-bar-item\n [groupId]=\"ACTION_BAR_GROUP_ID\"\n [priority]=\"ACTION_BAR_PRIORITY\"\n [placement]=\"'left'\"\n>\n <form\n class=\"d-flex\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n [hidden]=\"editMode$ | async\"\n (loading)=\"globalRefreshWidgetLoading = $event\"\n formControlName=\"autoRefresh\"\n ></c8y-auto-refresh-control>\n\n <c8y-auto-refresh-select-control\n [hidden]=\"editMode$ | async\"\n formControlName=\"autoRefreshSeconds\"\n ></c8y-auto-refresh-select-control>\n </form>\n <div class=\"input-group-btn\">\n @if (!(editMode$ | async)) {\n <button\n class=\"btn btn-default\"\n style=\"border-left: 0\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"globalRefreshWidgetLoading\"\n (click)=\"onRefresh()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': globalRefreshWidgetLoading }\"\n ></i>\n </button>\n }\n </div>\n</c8y-action-bar-item>\n" }]
|
|
32109
32207
|
}], propDecorators: { editMode$: [{
|
|
32110
32208
|
type: Input
|
|
32111
32209
|
}] } });
|
|
@@ -32145,7 +32243,7 @@ class WidgetsDashboardComponent {
|
|
|
32145
32243
|
get nativeElement() {
|
|
32146
32244
|
return this.elementRef.nativeElement;
|
|
32147
32245
|
}
|
|
32148
|
-
constructor(dynamic, translateService, route, modal, widgetGlobalAutoRefresh, router, elementRef) {
|
|
32246
|
+
constructor(dynamic, translateService, route, modal, widgetGlobalAutoRefresh, router, elementRef, cdr) {
|
|
32149
32247
|
this.dynamic = dynamic;
|
|
32150
32248
|
this.translateService = translateService;
|
|
32151
32249
|
this.route = route;
|
|
@@ -32153,6 +32251,7 @@ class WidgetsDashboardComponent {
|
|
|
32153
32251
|
this.widgetGlobalAutoRefresh = widgetGlobalAutoRefresh;
|
|
32154
32252
|
this.router = router;
|
|
32155
32253
|
this.elementRef = elementRef;
|
|
32254
|
+
this.cdr = cdr;
|
|
32156
32255
|
/**
|
|
32157
32256
|
* Indicates if device info in config should be overridden with values from context property.
|
|
32158
32257
|
*/
|
|
@@ -32189,6 +32288,23 @@ class WidgetsDashboardComponent {
|
|
|
32189
32288
|
this.widgetFullscreenChangeListener = null;
|
|
32190
32289
|
this.inFullScreen$ = fromEvent(document, 'fullscreenchange').pipe(map(() => this.fullScreen()), startWith(this.fullScreen()));
|
|
32191
32290
|
this.editMode$ = new BehaviorSubject(false);
|
|
32291
|
+
/**
|
|
32292
|
+
* When navigating AWAY from this dashboard to a different one, drop each widget's heavy content
|
|
32293
|
+
* (`intersected = false`) before Angular tears the view down. The widget bodies — the bulk of the
|
|
32294
|
+
* DOM — are removed from the lingering/detached dashboard tree, so the single detached
|
|
32295
|
+
* c8y-context-dashboard entry collapses toward its chrome shell instead of carrying a
|
|
32296
|
+
* multi-thousand-node subtree on every view change. (We intentionally do NOT remove the whole
|
|
32297
|
+
* grid: that orphans every card as a separate multi-root-retained fragment, which clutters the
|
|
32298
|
+
* Detached-elements panel worse and risks accumulating.) Robust across tab switches — the `@for`
|
|
32299
|
+
* just creates fresh children for the next dashboard. No remount cost on a real leave.
|
|
32300
|
+
*/
|
|
32301
|
+
this.clearWidgetContentOnLeave = true;
|
|
32302
|
+
/**
|
|
32303
|
+
* The cards blanked by the most recent {@link clearWidgetContentBeforeLeaving}, kept so a
|
|
32304
|
+
* cancelled/failed navigation can restore exactly those (and only those — never a card that was
|
|
32305
|
+
* legitimately below the fold and not yet intersected).
|
|
32306
|
+
*/
|
|
32307
|
+
this.clearedChildren = [];
|
|
32192
32308
|
this.copyDashboardLabel = gettext$1('Copy dashboard');
|
|
32193
32309
|
this.undoMessage = gettext$1('Undo: "{{ changeToUndo }}"');
|
|
32194
32310
|
this.redoMessage = gettext$1('Redo: "{{ changeToRedo }}"');
|
|
@@ -32199,6 +32315,17 @@ class WidgetsDashboardComponent {
|
|
|
32199
32315
|
if (navigation?.extras.state?.[NEW_DASHBOARD_ROUTER_STATE_PROP]) {
|
|
32200
32316
|
this.enableEditMode();
|
|
32201
32317
|
}
|
|
32318
|
+
this.router.events.pipe(takeUntilDestroyed()).subscribe(event => {
|
|
32319
|
+
if (event instanceof NavigationStart) {
|
|
32320
|
+
this.clearWidgetContentBeforeLeaving(event);
|
|
32321
|
+
}
|
|
32322
|
+
else if (event instanceof NavigationCancel || event instanceof NavigationError) {
|
|
32323
|
+
// The leave we blanked content for did not complete (e.g. a canDeactivate guard rejected
|
|
32324
|
+
// it, or back/forward was cancelled). This dashboard stays mounted, so restore exactly the
|
|
32325
|
+
// cards we cleared — otherwise they would remain permanently blank.
|
|
32326
|
+
this.restoreClearedWidgetContent();
|
|
32327
|
+
}
|
|
32328
|
+
});
|
|
32202
32329
|
this.resolvedWidgets$ = this._widgets.pipe(switchMap(widgets => this.executeResolversOfWidgets(widgets)), shareReplay(1));
|
|
32203
32330
|
this.isExecutingResolvers$ = merge(this._widgets.pipe(map(() => true)), this.resolvedWidgets$.pipe(map(() => false)));
|
|
32204
32331
|
this.isLoadingWidgets$ = combineLatest([this.isLoading$, this.isExecutingResolvers$]).pipe(map(loadings => loadings.some(loading => loading)), shareReplay(1));
|
|
@@ -32311,6 +32438,72 @@ class WidgetsDashboardComponent {
|
|
|
32311
32438
|
this.editMode$.next(true);
|
|
32312
32439
|
this.contextDashboard.historyDescription = {};
|
|
32313
32440
|
}
|
|
32441
|
+
/**
|
|
32442
|
+
* Clears widget content only when truly leaving this dashboard for a different one. Guards:
|
|
32443
|
+
* - opt-out flag;
|
|
32444
|
+
* - skip in edit mode (navigation may be cancelled by canDeactivate, and editing must keep content);
|
|
32445
|
+
* - skip when only the auxiliary outlet (e.g. the "Dashboard settings" drawer), query params
|
|
32446
|
+
* (auto-refresh / date range) or matrix params change — i.e. the PRIMARY dashboard route is the
|
|
32447
|
+
* same, so the dashboard stays mounted and must NOT be blanked.
|
|
32448
|
+
*/
|
|
32449
|
+
clearWidgetContentBeforeLeaving(event) {
|
|
32450
|
+
if (!this.clearWidgetContentOnLeave || this.editMode$.value) {
|
|
32451
|
+
return;
|
|
32452
|
+
}
|
|
32453
|
+
// Only when actually leaving THIS dashboard for a different primary route — not the settings
|
|
32454
|
+
// drawer (auxiliary outlet), query params (auto-refresh/date) or matrix params, which keep the
|
|
32455
|
+
// dashboard mounted and must NOT be blanked.
|
|
32456
|
+
if (this.toPrimaryPath(this.router.url) === this.toPrimaryPath(event.url)) {
|
|
32457
|
+
return;
|
|
32458
|
+
}
|
|
32459
|
+
const children = this.dashboardChildren;
|
|
32460
|
+
if (!children?.length) {
|
|
32461
|
+
return;
|
|
32462
|
+
}
|
|
32463
|
+
// Track only the cards that were actually showing content, so a cancelled navigation restores
|
|
32464
|
+
// exactly those and leaves never-intersected (below-the-fold) cards as they were.
|
|
32465
|
+
this.clearedChildren = children.filter(child => child.intersected);
|
|
32466
|
+
this.clearedChildren.forEach(child => (child.intersected = false));
|
|
32467
|
+
try {
|
|
32468
|
+
this.cdr.detectChanges();
|
|
32469
|
+
}
|
|
32470
|
+
catch {
|
|
32471
|
+
// The view may already be detaching during navigation; the content is dropped regardless.
|
|
32472
|
+
}
|
|
32473
|
+
}
|
|
32474
|
+
/**
|
|
32475
|
+
* Re-shows the cards blanked by a clear that was followed by a cancelled/failed navigation. The
|
|
32476
|
+
* IntersectionObserver one-shot-unobserves a visible card, so it cannot bring the content back on
|
|
32477
|
+
* its own; we restore `intersected` directly and re-arm observation for future scrolling.
|
|
32478
|
+
*/
|
|
32479
|
+
restoreClearedWidgetContent() {
|
|
32480
|
+
if (!this.clearedChildren.length) {
|
|
32481
|
+
return;
|
|
32482
|
+
}
|
|
32483
|
+
this.clearedChildren.forEach(child => {
|
|
32484
|
+
child.intersected = true;
|
|
32485
|
+
child.reobserve();
|
|
32486
|
+
});
|
|
32487
|
+
this.clearedChildren = [];
|
|
32488
|
+
try {
|
|
32489
|
+
this.cdr.detectChanges();
|
|
32490
|
+
}
|
|
32491
|
+
catch {
|
|
32492
|
+
// The view may be mid-teardown; restoring is best-effort.
|
|
32493
|
+
}
|
|
32494
|
+
}
|
|
32495
|
+
/**
|
|
32496
|
+
* Primary route path, parsed with the Router (not a hand-rolled regex) so query params, auxiliary
|
|
32497
|
+
* outlets (e.g. the dashboard-settings drawer `(dashboard-details:...)`) and matrix params are
|
|
32498
|
+
* correctly excluded. Two URLs with the same primary path mean the dashboard stays mounted
|
|
32499
|
+
* (settings/refresh/param change) — do not clear.
|
|
32500
|
+
*/
|
|
32501
|
+
toPrimaryPath(url) {
|
|
32502
|
+
const primary = this.router.parseUrl(url).root.children[PRIMARY_OUTLET];
|
|
32503
|
+
// Join only the path of each segment, dropping matrix params, so a matrix-param-only change
|
|
32504
|
+
// (which keeps the dashboard mounted) does not read as a different route.
|
|
32505
|
+
return primary ? `/${primary.segments.map(segment => segment.path).join('/')}` : '';
|
|
32506
|
+
}
|
|
32314
32507
|
exitFullScreen() {
|
|
32315
32508
|
const doc = document;
|
|
32316
32509
|
if (doc.exitFullscreen) {
|
|
@@ -32348,7 +32541,7 @@ class WidgetsDashboardComponent {
|
|
|
32348
32541
|
});
|
|
32349
32542
|
return true;
|
|
32350
32543
|
}
|
|
32351
|
-
catch
|
|
32544
|
+
catch {
|
|
32352
32545
|
return false;
|
|
32353
32546
|
}
|
|
32354
32547
|
}
|
|
@@ -32405,8 +32598,8 @@ class WidgetsDashboardComponent {
|
|
|
32405
32598
|
}
|
|
32406
32599
|
return result;
|
|
32407
32600
|
}
|
|
32408
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: WidgetsDashboardComponent, deps: [{ token: DynamicComponentService }, { token: i1$1.TranslateService }, { token: i1$4.ActivatedRoute }, { token: ModalService }, { token: WidgetGlobalAutoRefreshService }, { token: i1$4.Router }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32409
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: WidgetsDashboardComponent, isStandalone: true, selector: "c8y-widgets-dashboard", inputs: { widgets: "widgets", context: "context", contextDashboard: "contextDashboard", _settings: ["settings", "_settings"], isCopyDisabled: "isCopyDisabled", breadcrumb: "breadcrumb", editModeButtons: "editModeButtons", isSaveDisabled: "isSaveDisabled" }, outputs: { onAddWidget: "onAddWidget", onEditWidget: "onEditWidget", onDeleteWidget: "onDeleteWidget", onChangeDashboard: "onChangeDashboard", onResize: "onResize", onEditDashboard: "onEditDashboard", onCopyDashboard: "onCopyDashboard", onDeleteDashboard: "onDeleteDashboard", onChangeStart: "onChangeStart", onChangeEnd: "onChangeEnd", onSaveDashboard: "onSaveDashboard", onCancelDashboard: "onCancelDashboard", revertChange: "revertChange" }, host: { styleAttribute: "\n display: block;\n ", classAttribute: "dashboard c8y-grid-dashboard" }, providers: [WidgetsDashboardEventService], usesOnChanges: true, ngImport: i0, template: "@if (!!settings.title) {\n <c8y-title>\n @let dashboardTitle =\n settings.translateDashboardTitle ? (settings.title | translate) : settings.title;\n {{ dashboardTitle }}\n </c8y-title>\n}\n\n@if (!!breadcrumb) {\n <c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumb.icon\"\n [label]=\"breadcrumb.label\"\n [path]=\"breadcrumb.path\"\n ></c8y-breadcrumb-item>\n </c8y-breadcrumb>\n}\n\n@if (!(editMode$ | async)) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn hidden-xs\"\n title=\"{{ 'Edit widgets' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled\"\n (click)=\"enableEditMode()\"\n data-cy=\"c8y-widget-dashboard--edit-widgets\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (editMode$ | async) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"widget-dashboard--Add-widget\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add widget' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n itemClass=\"d-flex a-i-center gap-8\"\n >\n <div class=\"input-group input-group-sm animated fadeIn\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"\n editModeButtons.undoButtonDisabled\n ? ''\n : (undoMessage\n | translate: { changeToUndo: editModeButtons.changeToUndoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('undo')\"\n [disabled]=\"editModeButtons.undoButtonDisabled\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"\n editModeButtons.redoButtonDisabled\n ? ''\n : (redoMessage\n | translate: { changeToRedo: editModeButtons.changeToRedoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('redo')\"\n [disabled]=\"editModeButtons.redoButtonDisabled\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n </div>\n <span></span>\n </div>\n <div class=\"btn-group animated fadeIn\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancelDashboardSave()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm m-l-8\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"editModeButtons.undoButtonDisabled && isSaveDisabled\"\n (click)=\"saveDashboard()\"\n data-cy=\"c8y-widgets-dashboard--save\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </c8y-action-bar-item>\n}\n\n@if (onEditDashboard.observers.length) {\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link hidden-xs m-l-0\"\n title=\"{{ 'Dashboard settings' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n (click)=\"onEditDashboard.emit()\"\n data-cy=\"c8y-widgets-dashboard--edit-dashboard\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.allowFullscreen) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"-5000\"\n itemClass=\"pull-right\"\n >\n <button\n class=\"btn btn-link\"\n [attr.aria-label]=\"'Full screen' | translate\"\n tooltip=\"{{ 'Full screen' | translate }}\"\n placement=\"left\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"toggleFullscreen()\"\n data-cy=\"widgets-dashboard--Full-screen\"\n >\n <i [c8yIcon]=\"(inFullScreen$ | async) ? 'compress' : 'expand'\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visibile-lg-inline\">\n {{ 'Full screen' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canCopy) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-2000\"\n >\n <div class=\"d-flex a-i-center p-r-16\">\n <button\n class=\"hidden-xs\"\n title=\"{{\n (isCopyDisabled === true || !isCopyDisabled?.state ? 'Disabled' : copyDashboardLabel)\n | translate\n }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n data-cy=\"widgets-dashboard--copy-dashboard\"\n (click)=\"onCopyDashboard.emit()\"\n [disabled]=\"isCopyDisabled === true || !isCopyDisabled?.state || (editMode$ | async)\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n @if (!isCopyDisabled?.state && copyDisabledPopoverMsg) {\n <button\n class=\"btn-help btn-help--sm hidden-xs flex-no-shrink\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"copyDisabledPopoverMsg | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n data-cy=\"widgets-dashboard--info-copy-dashboard\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n ></button>\n }\n </div>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canDelete && onDeleteDashboard.observers.length) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-3000\"\n >\n <button\n class=\"hidden-xs\"\n title=\"{{ 'Delete dashboard' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n (click)=\"onDeleteDashboard.emit()\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard-mobile\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (!(isLoadingWidgets$ | async)) {\n @if (resolvedWidgets$ | async; as widgetsToDisplay) {\n <!-- empty state -->\n @if (widgetsToDisplay?.length === 0) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-device'\"\n [title]=\"'No widgets to display.' | translate\"\n >\n @if (onAddWidget.observers.length) {\n <div>\n @if (editMode$ | async) {\n <p translate>Add widgets to this dashboard.</p>\n }\n @if (!(editMode$ | async)) {\n <p translate>Click \"Edit widgets\" to unlock</p>\n }\n <div>\n @if (!settings.isDisabled && (editMode$ | async)) {\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"c8y-widgets-dashboard--add-widget\"\n translate\n >\n Add widget\n </button>\n }\n </div>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/working-with-dashboards\">user documentation</a>.\n </small>\n </p>\n </div>\n }\n </c8y-ui-empty-state>\n }\n\n <c8y-dashboard\n [columns]=\"settings.columns\"\n (dashboardChange)=\"onChangeDashboard.emit($event)\"\n #dashboard\n >\n @for (widget of widgetsToDisplay; track widget.id || widget.name || $index) {\n <c8y-dashboard-child\n [class]=\"widget.classes\"\n [x]=\"widget._x\"\n [y]=\"widget._y\"\n [width]=\"widget._width || settings.defaultWidth\"\n [height]=\"widget._height || settings.defaultHeight\"\n [margin]=\"settings.widgetMargin\"\n [data]=\"widget\"\n [useIntersection]=\"true\"\n [editMode]=\"editMode$ | async\"\n (changeStart)=\"\n onChangeStart.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n (changeEnd)=\"onChangeEnd.emit({ widget: widget, source: child, dashboard: dashboard })\"\n (toggleFullscreen)=\"toggleFullscreenOnWidget(child)\"\n [canToggleFullscreen]=\"!(inFullScreen$ | async) || widgetInFullscreenMode\"\n #child\n >\n @let widgetTitle =\n widget.title | translate: { noTranslateRemoveContext: !settings.translateWidgetTitle };\n <c8y-dashboard-child-title [attr.title]=\"widgetTitle\">\n <span data-cy=\"c8y-dashboard-list--device-widget\">\n {{ widgetTitle }}\n </span>\n </c8y-dashboard-child-title>\n @if (onEditWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Edit widget' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--Edit-widget\"\n (click)=\"onEditWidget.emit({ widget: widget, source: child, dashboard: dashboard })\"\n >\n <i c8yIcon=\"pencil\"></i>\n <span translate>Edit</span>\n </button>\n </c8y-dashboard-child-action>\n }\n @if (onDeleteWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Remove widget' | translate }}\"\n type=\"button\"\n data-cy=\"c8y-widgets-dashboard--remove-widget\"\n (click)=\"\n onDeleteWidget.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Remove</span>\n </button>\n </c8y-dashboard-child-action>\n }\n\n @if (child.intersected) {\n <c8y-dynamic-component\n [componentId]=\"widget.componentId || widget.name\"\n [config]=\"\n widget.templateUrl || widget.widgetComponent\n ? { child: widget, dashboard: contextDashboard, context: context }\n : widget.config\n \"\n (updateWidgetClasses)=\"updateWidgetClasses(widget, $event)\"\n ></c8y-dynamic-component>\n }\n </c8y-dashboard-child>\n }\n </c8y-dashboard>\n }\n} @else {\n <c8y-loading class=\"col-xs-12 text-center\"></c8y-loading>\n}\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$9.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "directive", type: GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: DashboardComponent, selector: "c8y-dashboard", inputs: ["columns", "gap", "rows"], outputs: ["dashboardChange"] }, { kind: "component", type: DashboardChildComponent, selector: "c8y-dashboard-child", inputs: ["x", "y", "width", "height", "data", "margin", "useIntersection", "isFrozen", "canToggleFullscreen", "editMode", "class"], outputs: ["changeStart", "changeEnd", "toggleFullscreen"] }, { kind: "component", type: DashboardChildTitleComponent, selector: "c8y-dashboard-child-title" }, { kind: "component", type: DashboardChildActionComponent, selector: "c8y-dashboard-child-action" }, { kind: "component", type: DynamicComponentComponent, selector: "c8y-dynamic-component", inputs: ["componentId", "config", "mode", "notFoundError", "executeResolvers"], outputs: ["updateWidgetClasses"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
32601
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: WidgetsDashboardComponent, deps: [{ token: DynamicComponentService }, { token: i1$1.TranslateService }, { token: i1$4.ActivatedRoute }, { token: ModalService }, { token: WidgetGlobalAutoRefreshService }, { token: i1$4.Router }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32602
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: WidgetsDashboardComponent, isStandalone: true, selector: "c8y-widgets-dashboard", inputs: { widgets: "widgets", context: "context", contextDashboard: "contextDashboard", _settings: ["settings", "_settings"], isCopyDisabled: "isCopyDisabled", breadcrumb: "breadcrumb", editModeButtons: "editModeButtons", isSaveDisabled: "isSaveDisabled", clearWidgetContentOnLeave: "clearWidgetContentOnLeave" }, outputs: { onAddWidget: "onAddWidget", onEditWidget: "onEditWidget", onDeleteWidget: "onDeleteWidget", onChangeDashboard: "onChangeDashboard", onResize: "onResize", onEditDashboard: "onEditDashboard", onCopyDashboard: "onCopyDashboard", onDeleteDashboard: "onDeleteDashboard", onChangeStart: "onChangeStart", onChangeEnd: "onChangeEnd", onSaveDashboard: "onSaveDashboard", onCancelDashboard: "onCancelDashboard", revertChange: "revertChange" }, host: { styleAttribute: "\n display: block;\n ", classAttribute: "dashboard c8y-grid-dashboard" }, providers: [WidgetsDashboardEventService], viewQueries: [{ propertyName: "dashboardChildren", predicate: DashboardChildComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (!!settings.title) {\n <c8y-title>\n @let dashboardTitle =\n settings.translateDashboardTitle ? (settings.title | translate) : settings.title;\n {{ dashboardTitle }}\n </c8y-title>\n}\n\n@if (!!breadcrumb) {\n <c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumb.icon\"\n [label]=\"breadcrumb.label\"\n [path]=\"breadcrumb.path\"\n ></c8y-breadcrumb-item>\n </c8y-breadcrumb>\n}\n\n@if (!(editMode$ | async)) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn hidden-xs\"\n title=\"{{ 'Edit widgets' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled\"\n (click)=\"enableEditMode()\"\n data-cy=\"c8y-widget-dashboard--edit-widgets\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (editMode$ | async) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"widget-dashboard--Add-widget\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add widget' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n itemClass=\"d-flex a-i-center gap-8\"\n >\n <div class=\"input-group input-group-sm animated fadeIn\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"\n editModeButtons.undoButtonDisabled\n ? ''\n : (undoMessage\n | translate: { changeToUndo: editModeButtons.changeToUndoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('undo')\"\n [disabled]=\"editModeButtons.undoButtonDisabled\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"\n editModeButtons.redoButtonDisabled\n ? ''\n : (redoMessage\n | translate: { changeToRedo: editModeButtons.changeToRedoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('redo')\"\n [disabled]=\"editModeButtons.redoButtonDisabled\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n </div>\n <span></span>\n </div>\n <div class=\"btn-group animated fadeIn\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancelDashboardSave()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm m-l-8\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"editModeButtons.undoButtonDisabled && isSaveDisabled\"\n (click)=\"saveDashboard()\"\n data-cy=\"c8y-widgets-dashboard--save\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </c8y-action-bar-item>\n}\n\n@if (onEditDashboard.observers.length) {\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link hidden-xs m-l-0\"\n title=\"{{ 'Dashboard settings' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n (click)=\"onEditDashboard.emit()\"\n data-cy=\"c8y-widgets-dashboard--edit-dashboard\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.allowFullscreen) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"-5000\"\n itemClass=\"pull-right\"\n >\n <button\n class=\"btn btn-link\"\n [attr.aria-label]=\"'Full screen' | translate\"\n tooltip=\"{{ 'Full screen' | translate }}\"\n placement=\"left\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"toggleFullscreen()\"\n data-cy=\"widgets-dashboard--Full-screen\"\n >\n <i [c8yIcon]=\"(inFullScreen$ | async) ? 'compress' : 'expand'\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visibile-lg-inline\">\n {{ 'Full screen' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canCopy) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-2000\"\n >\n <div class=\"d-flex a-i-center p-r-16\">\n <button\n class=\"hidden-xs\"\n title=\"{{\n (isCopyDisabled === true || !isCopyDisabled?.state ? 'Disabled' : copyDashboardLabel)\n | translate\n }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n data-cy=\"widgets-dashboard--copy-dashboard\"\n (click)=\"onCopyDashboard.emit()\"\n [disabled]=\"isCopyDisabled === true || !isCopyDisabled?.state || (editMode$ | async)\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n @if (!isCopyDisabled?.state && copyDisabledPopoverMsg) {\n <button\n class=\"btn-help btn-help--sm hidden-xs flex-no-shrink\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"copyDisabledPopoverMsg | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n data-cy=\"widgets-dashboard--info-copy-dashboard\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n ></button>\n }\n </div>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canDelete && onDeleteDashboard.observers.length) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-3000\"\n >\n <button\n class=\"hidden-xs\"\n title=\"{{ 'Delete dashboard' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n (click)=\"onDeleteDashboard.emit()\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard-mobile\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (!(isLoadingWidgets$ | async)) {\n @if (resolvedWidgets$ | async; as widgetsToDisplay) {\n <!-- empty state -->\n @if (widgetsToDisplay?.length === 0) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-device'\"\n [title]=\"'No widgets to display.' | translate\"\n >\n @if (onAddWidget.observers.length) {\n <div>\n @if (editMode$ | async) {\n <p translate>Add widgets to this dashboard.</p>\n }\n @if (!(editMode$ | async)) {\n <p translate>Click \"Edit widgets\" to unlock</p>\n }\n <div>\n @if (!settings.isDisabled && (editMode$ | async)) {\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"c8y-widgets-dashboard--add-widget\"\n translate\n >\n Add widget\n </button>\n }\n </div>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/working-with-dashboards\">user documentation</a>.\n </small>\n </p>\n </div>\n }\n </c8y-ui-empty-state>\n }\n\n <c8y-dashboard\n [columns]=\"settings.columns\"\n (dashboardChange)=\"onChangeDashboard.emit($event)\"\n #dashboard\n >\n @for (widget of widgetsToDisplay; track widget.id || widget.name || $index) {\n <c8y-dashboard-child\n [class]=\"widget.classes\"\n [x]=\"widget._x\"\n [y]=\"widget._y\"\n [width]=\"widget._width || settings.defaultWidth\"\n [height]=\"widget._height || settings.defaultHeight\"\n [margin]=\"settings.widgetMargin\"\n [data]=\"widget\"\n [useIntersection]=\"true\"\n [editMode]=\"editMode$ | async\"\n (changeStart)=\"\n onChangeStart.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n (changeEnd)=\"onChangeEnd.emit({ widget: widget, source: child, dashboard: dashboard })\"\n (toggleFullscreen)=\"toggleFullscreenOnWidget(child)\"\n [canToggleFullscreen]=\"!(inFullScreen$ | async) || widgetInFullscreenMode\"\n #child\n >\n @let widgetTitle =\n widget.title | translate: { noTranslateRemoveContext: !settings.translateWidgetTitle };\n <c8y-dashboard-child-title [attr.title]=\"widgetTitle\">\n <span data-cy=\"c8y-dashboard-list--device-widget\">\n {{ widgetTitle }}\n </span>\n </c8y-dashboard-child-title>\n @if (onEditWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Edit widget' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--Edit-widget\"\n (click)=\"onEditWidget.emit({ widget: widget, source: child, dashboard: dashboard })\"\n >\n <i c8yIcon=\"pencil\"></i>\n <span translate>Edit</span>\n </button>\n </c8y-dashboard-child-action>\n }\n @if (onDeleteWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Remove widget' | translate }}\"\n type=\"button\"\n data-cy=\"c8y-widgets-dashboard--remove-widget\"\n (click)=\"\n onDeleteWidget.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Remove</span>\n </button>\n </c8y-dashboard-child-action>\n }\n\n @if (child.intersected) {\n <c8y-dynamic-component\n [componentId]=\"widget.componentId || widget.name\"\n [config]=\"\n widget.templateUrl || widget.widgetComponent\n ? { child: widget, dashboard: contextDashboard, context: context }\n : widget.config\n \"\n (updateWidgetClasses)=\"updateWidgetClasses(widget, $event)\"\n ></c8y-dynamic-component>\n }\n </c8y-dashboard-child>\n }\n </c8y-dashboard>\n }\n} @else {\n <c8y-loading class=\"col-xs-12 text-center\"></c8y-loading>\n}\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$9.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "directive", type: GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: DashboardComponent, selector: "c8y-dashboard", inputs: ["columns", "gap", "rows"], outputs: ["dashboardChange"] }, { kind: "component", type: DashboardChildComponent, selector: "c8y-dashboard-child", inputs: ["x", "y", "width", "height", "data", "margin", "useIntersection", "isFrozen", "canToggleFullscreen", "editMode", "class"], outputs: ["changeStart", "changeEnd", "toggleFullscreen"] }, { kind: "component", type: DashboardChildTitleComponent, selector: "c8y-dashboard-child-title" }, { kind: "component", type: DashboardChildActionComponent, selector: "c8y-dashboard-child-action" }, { kind: "component", type: DynamicComponentComponent, selector: "c8y-dynamic-component", inputs: ["componentId", "config", "mode", "notFoundError", "executeResolvers"], outputs: ["updateWidgetClasses"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
32410
32603
|
}
|
|
32411
32604
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: WidgetsDashboardComponent, decorators: [{
|
|
32412
32605
|
type: Component,
|
|
@@ -32440,7 +32633,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
32440
32633
|
C8yTranslatePipe,
|
|
32441
32634
|
AsyncPipe
|
|
32442
32635
|
], template: "@if (!!settings.title) {\n <c8y-title>\n @let dashboardTitle =\n settings.translateDashboardTitle ? (settings.title | translate) : settings.title;\n {{ dashboardTitle }}\n </c8y-title>\n}\n\n@if (!!breadcrumb) {\n <c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumb.icon\"\n [label]=\"breadcrumb.label\"\n [path]=\"breadcrumb.path\"\n ></c8y-breadcrumb-item>\n </c8y-breadcrumb>\n}\n\n@if (!(editMode$ | async)) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn hidden-xs\"\n title=\"{{ 'Edit widgets' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled\"\n (click)=\"enableEditMode()\"\n data-cy=\"c8y-widget-dashboard--edit-widgets\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"send-backward\"></i>\n <span class=\"m-l-4\">{{ 'Edit widgets' | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (editMode$ | async) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n >\n <button\n class=\"btn btn-link animated fadeIn\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"widget-dashboard--Add-widget\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add widget' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"ACTION_BAR_EDIT_WIDGETS_PRIORITY\"\n itemClass=\"d-flex a-i-center gap-8\"\n >\n <div class=\"input-group input-group-sm animated fadeIn\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"\n editModeButtons.undoButtonDisabled\n ? ''\n : (undoMessage\n | translate: { changeToUndo: editModeButtons.changeToUndoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('undo')\"\n [disabled]=\"editModeButtons.undoButtonDisabled\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm btn-icon\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"\n editModeButtons.redoButtonDisabled\n ? ''\n : (redoMessage\n | translate: { changeToRedo: editModeButtons.changeToRedoName | translate })\n \"\n container=\"body\"\n (click)=\"revertChange.emit('redo')\"\n [disabled]=\"editModeButtons.redoButtonDisabled\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n </div>\n <span></span>\n </div>\n <div class=\"btn-group animated fadeIn\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancelDashboardSave()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm m-l-8\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"editModeButtons.undoButtonDisabled && isSaveDisabled\"\n (click)=\"saveDashboard()\"\n data-cy=\"c8y-widgets-dashboard--save\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </c8y-action-bar-item>\n}\n\n@if (onEditDashboard.observers.length) {\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link hidden-xs m-l-0\"\n title=\"{{ 'Dashboard settings' | translate }}\"\n type=\"button\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n (click)=\"onEditDashboard.emit()\"\n data-cy=\"c8y-widgets-dashboard--edit-dashboard\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n <button\n class=\"btn btn-link visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"sorting-slider\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visible-lg-inline\">\n {{ 'Dashboard settings' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.allowFullscreen) {\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"-5000\"\n itemClass=\"pull-right\"\n >\n <button\n class=\"btn btn-link\"\n [attr.aria-label]=\"'Full screen' | translate\"\n tooltip=\"{{ 'Full screen' | translate }}\"\n placement=\"left\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"toggleFullscreen()\"\n data-cy=\"widgets-dashboard--Full-screen\"\n >\n <i [c8yIcon]=\"(inFullScreen$ | async) ? 'compress' : 'expand'\"></i>\n <span class=\"visible-xs-inline hidden-sm visible-md-inline visibile-lg-inline\">\n {{ 'Full screen' | translate }}\n </span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canCopy) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-2000\"\n >\n <div class=\"d-flex a-i-center p-r-16\">\n <button\n class=\"hidden-xs\"\n title=\"{{\n (isCopyDisabled === true || !isCopyDisabled?.state ? 'Disabled' : copyDashboardLabel)\n | translate\n }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n data-cy=\"widgets-dashboard--copy-dashboard\"\n (click)=\"onCopyDashboard.emit()\"\n [disabled]=\"isCopyDisabled === true || !isCopyDisabled?.state || (editMode$ | async)\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n @if (!isCopyDisabled?.state && copyDisabledPopoverMsg) {\n <button\n class=\"btn-help btn-help--sm hidden-xs flex-no-shrink\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"copyDisabledPopoverMsg | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n data-cy=\"widgets-dashboard--info-copy-dashboard\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n ></button>\n }\n </div>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn btn-link': !settings.canDelete }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"clone\"></i>\n <span>{{ copyDashboardLabel | translate }}</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (settings.canDelete && onDeleteDashboard.observers.length) {\n <c8y-action-bar-item\n [placement]=\"'more'\"\n [priority]=\"-3000\"\n >\n <button\n class=\"hidden-xs\"\n title=\"{{ 'Delete dashboard' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n (click)=\"onDeleteDashboard.emit()\"\n [disabled]=\"settings.isDisabled || (editMode$ | async)\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n <button\n class=\"visible-xs m-l-0\"\n tooltip=\"{{ 'Not available on mobile phone' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--delete-dashboard-mobile\"\n [ngClass]=\"{ 'btn btn-link': !settings.canCopy }\"\n [disabled]=\"true\"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Delete dashboard</span>\n </button>\n </c8y-action-bar-item>\n}\n\n@if (!(isLoadingWidgets$ | async)) {\n @if (resolvedWidgets$ | async; as widgetsToDisplay) {\n <!-- empty state -->\n @if (widgetsToDisplay?.length === 0) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-device'\"\n [title]=\"'No widgets to display.' | translate\"\n >\n @if (onAddWidget.observers.length) {\n <div>\n @if (editMode$ | async) {\n <p translate>Add widgets to this dashboard.</p>\n }\n @if (!(editMode$ | async)) {\n <p translate>Click \"Edit widgets\" to unlock</p>\n }\n <div>\n @if (!settings.isDisabled && (editMode$ | async)) {\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Add widget' | translate }}\"\n type=\"button\"\n (click)=\"onAddWidget.emit()\"\n data-cy=\"c8y-widgets-dashboard--add-widget\"\n translate\n >\n Add widget\n </button>\n }\n </div>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/working-with-dashboards\">user documentation</a>.\n </small>\n </p>\n </div>\n }\n </c8y-ui-empty-state>\n }\n\n <c8y-dashboard\n [columns]=\"settings.columns\"\n (dashboardChange)=\"onChangeDashboard.emit($event)\"\n #dashboard\n >\n @for (widget of widgetsToDisplay; track widget.id || widget.name || $index) {\n <c8y-dashboard-child\n [class]=\"widget.classes\"\n [x]=\"widget._x\"\n [y]=\"widget._y\"\n [width]=\"widget._width || settings.defaultWidth\"\n [height]=\"widget._height || settings.defaultHeight\"\n [margin]=\"settings.widgetMargin\"\n [data]=\"widget\"\n [useIntersection]=\"true\"\n [editMode]=\"editMode$ | async\"\n (changeStart)=\"\n onChangeStart.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n (changeEnd)=\"onChangeEnd.emit({ widget: widget, source: child, dashboard: dashboard })\"\n (toggleFullscreen)=\"toggleFullscreenOnWidget(child)\"\n [canToggleFullscreen]=\"!(inFullScreen$ | async) || widgetInFullscreenMode\"\n #child\n >\n @let widgetTitle =\n widget.title | translate: { noTranslateRemoveContext: !settings.translateWidgetTitle };\n <c8y-dashboard-child-title [attr.title]=\"widgetTitle\">\n <span data-cy=\"c8y-dashboard-list--device-widget\">\n {{ widgetTitle }}\n </span>\n </c8y-dashboard-child-title>\n @if (onEditWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Edit widget' | translate }}\"\n type=\"button\"\n data-cy=\"widgets-dashboard--Edit-widget\"\n (click)=\"onEditWidget.emit({ widget: widget, source: child, dashboard: dashboard })\"\n >\n <i c8yIcon=\"pencil\"></i>\n <span translate>Edit</span>\n </button>\n </c8y-dashboard-child-action>\n }\n @if (onDeleteWidget.observers.length) {\n <c8y-dashboard-child-action>\n <button\n title=\"{{ 'Remove widget' | translate }}\"\n type=\"button\"\n data-cy=\"c8y-widgets-dashboard--remove-widget\"\n (click)=\"\n onDeleteWidget.emit({ widget: widget, source: child, dashboard: dashboard })\n \"\n >\n <i c8yIcon=\"delete\"></i>\n <span translate>Remove</span>\n </button>\n </c8y-dashboard-child-action>\n }\n\n @if (child.intersected) {\n <c8y-dynamic-component\n [componentId]=\"widget.componentId || widget.name\"\n [config]=\"\n widget.templateUrl || widget.widgetComponent\n ? { child: widget, dashboard: contextDashboard, context: context }\n : widget.config\n \"\n (updateWidgetClasses)=\"updateWidgetClasses(widget, $event)\"\n ></c8y-dynamic-component>\n }\n </c8y-dashboard-child>\n }\n </c8y-dashboard>\n }\n} @else {\n <c8y-loading class=\"col-xs-12 text-center\"></c8y-loading>\n}\n" }]
|
|
32443
|
-
}], ctorParameters: () => [{ type: DynamicComponentService }, { type: i1$1.TranslateService }, { type: i1$4.ActivatedRoute }, { type: ModalService }, { type: WidgetGlobalAutoRefreshService }, { type: i1$4.Router }, { type: i0.ElementRef }], propDecorators: { widgets: [{
|
|
32636
|
+
}], ctorParameters: () => [{ type: DynamicComponentService }, { type: i1$1.TranslateService }, { type: i1$4.ActivatedRoute }, { type: ModalService }, { type: WidgetGlobalAutoRefreshService }, { type: i1$4.Router }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { widgets: [{
|
|
32444
32637
|
type: Input
|
|
32445
32638
|
}], context: [{
|
|
32446
32639
|
type: Input
|
|
@@ -32483,6 +32676,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
32483
32676
|
type: Output
|
|
32484
32677
|
}], revertChange: [{
|
|
32485
32678
|
type: Output
|
|
32679
|
+
}], dashboardChildren: [{
|
|
32680
|
+
type: ViewChildren,
|
|
32681
|
+
args: [DashboardChildComponent]
|
|
32682
|
+
}], clearWidgetContentOnLeave: [{
|
|
32683
|
+
type: Input
|
|
32486
32684
|
}] } });
|
|
32487
32685
|
|
|
32488
32686
|
class HelpService {
|