@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
257 lines (250 loc) • 22.9 kB
JavaScript
import * as i0 from '@angular/core';
import { Input, Directive, EventEmitter, ViewChild, ContentChildren, Output, Component, NgModule } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import * as i2 from '@c8y/ngx-components';
import { gettext, Status, C8yStepper, CoreModule } from '@c8y/ngx-components';
import * as i1 from '@c8y/ngx-components/operations/bulk-operations-service';
import * as i6 from '@c8y/ngx-components/operations/create-bulk-operation-details';
import { CreateBulkOperationDetailsComponent, CreateBulkOperationDetailsModule } from '@c8y/ngx-components/operations/create-bulk-operation-details';
import { BULK_OPERATION_EVENT } from '@c8y/ngx-components/operations/product-experience';
import { get } from 'lodash-es';
import * as i3 from '@angular/common';
import * as i4 from '@angular/cdk/stepper';
import * as i5 from '@c8y/ngx-components/operations/device-selector';
import { DeviceSelectorModule } from '@c8y/ngx-components/operations/device-selector';
import * as i7 from '@c8y/ngx-components/operations/operation-summary';
import { OperationSummaryModule } from '@c8y/ngx-components/operations/operation-summary';
class CustomStep {
constructor(templateRef) {
this.templateRef = templateRef;
this.buttonsDisabled = false;
this.onNext = ({ stepper, step }) => {
// steps without own `onNext` handler, e.g. preview steps need to mark themselves as `completed`,
// otherwise stepper will not allow to move forth from them as soon as the user navigates back
// and the `c8y-stepper-buttons` component marks the step as incomplete.
step.completed = true;
stepper.next();
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CustomStep, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: CustomStep, isStandalone: false, selector: "[customStep]", inputs: { label: ["customStep", "label"], completed: ["customStepCompleted", "completed"], buttonsDisabled: ["customStepButtonsDisabled", "buttonsDisabled"], onNext: ["customStepOnNext", "onNext"] }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CustomStep, decorators: [{
type: Directive,
args: [{
selector: '[customStep]',
standalone: false
}]
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { label: [{
type: Input,
args: ['customStep']
}], completed: [{
type: Input,
args: ['customStepCompleted']
}], buttonsDisabled: [{
type: Input,
args: ['customStepButtonsDisabled']
}], onNext: [{
type: Input,
args: ['customStepOnNext']
}] } });
class BulkOperationStepper {
constructor(bulkOperationService, modal, alert) {
this.bulkOperationService = bulkOperationService;
this.modal = modal;
this.alert = alert;
this.BULK_OPERATION_EVENT = BULK_OPERATION_EVENT;
this.selectionChange = new EventEmitter();
this.steps = [];
this.showStepper = false;
this.showButtons = false;
this.stepperButtonsLabels = { custom: gettext('Schedule') };
this.deviceTypesSubject$ = new Subject();
this.endSubscriptions = new Subject();
this.deviceTypes$ = this.deviceTypesSubject$.asObservable();
}
ngAfterViewInit() {
setTimeout(() => {
// wait for the next event loop turn as `steps` has already been checked in this CD cycle
this.steps = this.customSteps.toArray();
this.showStepper = true;
setTimeout(() => {
// postpone rendering of buttons for custom steps to the point where custom steps have already been rendered
this.showButtons = true;
if (this.stepper) {
this.stepper.selectionChange.pipe(takeUntil(this.endSubscriptions)).subscribe(event => {
this.selectionChange.next(event);
});
this.operationDetailsForm =
this.createBulkOperationDetailsComponent.fgOperationDescription;
}
});
});
}
changeDeviceTypes(deviceTypes) {
if (deviceTypes) {
this.deviceTypesSubject$.next(Array.isArray(deviceTypes) ? deviceTypes : [deviceTypes]);
}
else {
this.deviceTypesSubject$.next([]);
}
}
async confirmDeviceSelection($event) {
if (!this.deviceQueryString) {
try {
await this.modal.confirm(gettext('All devices selected'), gettext('You are about to schedule the bulk operation to be executed for all devices. Do you want to proceed?'), Status.WARNING, { ok: gettext('Schedule for all devices'), cancel: gettext('Cancel and select devices') });
$event.step.completed = true;
$event.stepper.next();
this.operationDetails = this.retrieveOperationDetails
? await this.retrieveOperationDetails()
: undefined;
}
catch (ex) {
// Intentionally empty
}
}
else {
$event.step.completed = true;
$event.stepper.next();
this.operationDetails = this.retrieveOperationDetails
? await this.retrieveOperationDetails()
: undefined;
}
this.bulkOperationType = this.bulkOperationService.retrieveBulkOperationType(get(this.operationDetails, 'prototype'));
if (this.operationDetailsForm &&
get(this.operationDetailsForm, 'controls.description.pristine') &&
this.operationDetails) {
this.operationDetailsForm.patchValue({
description: get(this.operationDetails, 'prototype.description')
});
}
}
cancel() {
this.close();
}
async scheduleBulkOperation() {
this.pendingStatus = true;
try {
this.operationDetails.prototype.description = get(this.operationDetailsForm, 'controls.description.value');
this.operationDetails.note = get(this.operationDetailsForm, 'controls.note.value');
this.operationDetails.schedule = get(this.operationDetailsForm, 'controls.schedule.value');
await this.bulkOperationService.scheduleBulkOperation(this.deviceQueryString, this.operationDetails);
this.alert.success(gettext('New bulk operation scheduled.'));
this.close();
}
catch (ex) {
this.alert.addServerFailure(ex);
}
this.pendingStatus = false;
}
ngOnDestroy() {
this.endSubscriptions.next();
this.endSubscriptions.complete();
}
close() {
this.stepper.reset();
this.bulkOperationService.returnToBulkOperationOverview();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepper, deps: [{ token: i1.BulkOperationsService }, { token: i2.ModalService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: BulkOperationStepper, isStandalone: false, selector: "c8y-bulk-operation-stepper", inputs: { type: "type" }, outputs: { selectionChange: "selectionChange" }, queries: [{ propertyName: "customSteps", predicate: CustomStep }], viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true }, { propertyName: "createBulkOperationDetailsComponent", first: true, predicate: CreateBulkOperationDetailsComponent, descendants: true }], ngImport: i0, template: "<div class=\"fit-h\">\n <c8y-stepper\n class=\"d-col no-align-items fit-h c8y-stepper--no-btns a-i-center\"\n linear\n [disableDefaultIcons]=\"{ edit: true, done: false }\"\n [customClasses]=\"['col-xs-10', 'col-sm-8', 'm-t-24', 'm-b-40', 'p-0', 'flex-no-shrink']\"\n *ngIf=\"showStepper\"\n c8yProductExperience\n [actionName]=\"BULK_OPERATION_EVENT\"\n [actionData]=\"{ bulkOperationType: type }\"\n >\n <!-- CUSTOM STEPS 1 to N-2 -->\n <cdk-step\n *ngFor=\"let step of steps\"\n [label]=\"step.label | translate\"\n [completed]=\"step.completed\"\n >\n <ng-container *ngTemplateOutlet=\"step.templateRef\"></ng-container>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [disabled]=\"step.buttonsDisabled\"\n (onNext)=\"step.onNext($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <!-- STEP N-1 - Data-grid -->\n <cdk-step [label]=\"'Filter target devices' | translate\">\n <div class=\"card-block p-b-0 p-t-0 flex-no-shrink separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Filter target devices' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <c8y-device-selector\n [deviceTypes]=\"deviceTypes$\"\n (onDeviceQueryStringChange)=\"deviceQueryString = $event\"\n ></c8y-device-selector>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n (onNext)=\"confirmDeviceSelection($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <!-- STEP N - Scheduler -->\n <cdk-step [label]=\"'Confirm and schedule bulk operation' | translate\">\n <div class=\"card-block flex-no-shrink p-b-0 p-t-0 separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Confirm and schedule bulk operation' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <div class=\"card-inner-scroll fit-h\">\n <div class=\"card-block p-b-0\">\n <div class=\"d-flex j-c-center p-t-8 p-b-8\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-operation-summary\n [name]=\"operationDetails?.name | translate\"\n [description]=\"operationDetails?.description | translate\"\n [deviceQueryString]=\"deviceQueryString\"\n ></c8y-operation-summary>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-create-bulk-operation-details\n [bulkOperationType]=\"bulkOperationType\"\n ></c8y-create-bulk-operation-details>\n </div>\n </div>\n </div>\n </div>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [labels]=\"stepperButtonsLabels\"\n [pending]=\"pendingStatus\"\n [disabled]=\"operationDetailsForm?.invalid\"\n (onCancel)=\"cancel()\"\n (onCustom)=\"scheduleBulkOperation()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</div>\n", dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.C8yStepper, selector: "c8y-stepper", inputs: ["disableDefaultIcons", "disableProgressButtons", "customClasses", "hideStepProgress", "useStepLabelsAsTitlesOnly"], outputs: ["onStepChange"] }, { kind: "component", type: i4.CdkStep, selector: "cdk-step", inputs: ["stepControl", "label", "errorMessage", "aria-label", "aria-labelledby", "state", "editable", "optional", "completed", "hasError"], outputs: ["interacted"], exportAs: ["cdkStep"] }, { kind: "component", type: i2.C8yStepperButtons, selector: "c8y-stepper-buttons", inputs: ["labels", "pending", "disabled", "showButtons"], outputs: ["onCancel", "onNext", "onBack", "onCustom"] }, { kind: "directive", type: i2.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i5.DeviceSelectorComponent, selector: "c8y-device-selector", inputs: ["deviceTypes"], outputs: ["onDeviceQueryStringChange"] }, { kind: "component", type: i6.CreateBulkOperationDetailsComponent, selector: "c8y-create-bulk-operation-details", inputs: ["bulkOperationType"] }, { kind: "component", type: i7.OperationSummaryComponent, selector: "c8y-operation-summary", inputs: ["name", "description", "deviceQueryString"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepper, decorators: [{
type: Component,
args: [{ selector: 'c8y-bulk-operation-stepper', standalone: false, template: "<div class=\"fit-h\">\n <c8y-stepper\n class=\"d-col no-align-items fit-h c8y-stepper--no-btns a-i-center\"\n linear\n [disableDefaultIcons]=\"{ edit: true, done: false }\"\n [customClasses]=\"['col-xs-10', 'col-sm-8', 'm-t-24', 'm-b-40', 'p-0', 'flex-no-shrink']\"\n *ngIf=\"showStepper\"\n c8yProductExperience\n [actionName]=\"BULK_OPERATION_EVENT\"\n [actionData]=\"{ bulkOperationType: type }\"\n >\n <!-- CUSTOM STEPS 1 to N-2 -->\n <cdk-step\n *ngFor=\"let step of steps\"\n [label]=\"step.label | translate\"\n [completed]=\"step.completed\"\n >\n <ng-container *ngTemplateOutlet=\"step.templateRef\"></ng-container>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [disabled]=\"step.buttonsDisabled\"\n (onNext)=\"step.onNext($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <!-- STEP N-1 - Data-grid -->\n <cdk-step [label]=\"'Filter target devices' | translate\">\n <div class=\"card-block p-b-0 p-t-0 flex-no-shrink separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Filter target devices' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <c8y-device-selector\n [deviceTypes]=\"deviceTypes$\"\n (onDeviceQueryStringChange)=\"deviceQueryString = $event\"\n ></c8y-device-selector>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n (onNext)=\"confirmDeviceSelection($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <!-- STEP N - Scheduler -->\n <cdk-step [label]=\"'Confirm and schedule bulk operation' | translate\">\n <div class=\"card-block flex-no-shrink p-b-0 p-t-0 separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Confirm and schedule bulk operation' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <div class=\"card-inner-scroll fit-h\">\n <div class=\"card-block p-b-0\">\n <div class=\"d-flex j-c-center p-t-8 p-b-8\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-operation-summary\n [name]=\"operationDetails?.name | translate\"\n [description]=\"operationDetails?.description | translate\"\n [deviceQueryString]=\"deviceQueryString\"\n ></c8y-operation-summary>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-create-bulk-operation-details\n [bulkOperationType]=\"bulkOperationType\"\n ></c8y-create-bulk-operation-details>\n </div>\n </div>\n </div>\n </div>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [labels]=\"stepperButtonsLabels\"\n [pending]=\"pendingStatus\"\n [disabled]=\"operationDetailsForm?.invalid\"\n (onCancel)=\"cancel()\"\n (onCustom)=\"scheduleBulkOperation()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.BulkOperationsService }, { type: i2.ModalService }, { type: i2.AlertService }], propDecorators: { type: [{
type: Input
}], selectionChange: [{
type: Output
}], customSteps: [{
type: ContentChildren,
args: [CustomStep]
}], stepper: [{
type: ViewChild,
args: [C8yStepper, { static: false }]
}], createBulkOperationDetailsComponent: [{
type: ViewChild,
args: [CreateBulkOperationDetailsComponent, { static: false }]
}] } });
class BaseStepperComponent {
constructor() {
/**
* A map holding step data. The order of properties need to match the order of
* the steps they hold data for as the index of the property is used to clear
* step data when navigating forth after changing data at an earlier step.
*/
this.stepData = {};
this.endSubscriptions = new Subject();
}
set deviceTypes(deviceTypes) {
if (this.operationStepper) {
this.operationStepper.changeDeviceTypes(deviceTypes);
}
}
ngOnInit() {
this.operationStepper.retrieveOperationDetails = this.retrieveOperationPrototype.bind(this);
this.operationStepper.selectionChange
.pipe(takeUntil(this.endSubscriptions))
.subscribe(this.onSelectionChange.bind(this));
}
ngOnDestroy() {
this.endSubscriptions.next();
this.endSubscriptions.complete();
}
onSelectionChange(event) {
const { selectedIndex, previouslySelectedIndex } = event;
if (selectedIndex > previouslySelectedIndex &&
selectedIndex < Object.keys(this.stepData).length) {
// TODO clear step data only if previous step is "dirty"
this.stepData[this.getStepDataKeyByIndex(selectedIndex)] = undefined;
}
}
getStepDataKeyByIndex(index) {
return Object.keys(this.stepData)[index];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BaseStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: BaseStepperComponent, isStandalone: false, selector: "c8y-base-stepper", viewQueries: [{ propertyName: "operationStepper", first: true, predicate: BulkOperationStepper, descendants: true, static: true }], ngImport: i0, template: '', isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BaseStepperComponent, decorators: [{
type: Component,
args: [{
selector: 'c8y-base-stepper',
template: '',
standalone: false
}]
}], propDecorators: { operationStepper: [{
type: ViewChild,
args: [BulkOperationStepper, { static: true }]
}] } });
/**
* This module provides base stepper class and stepper wrapper component.
*/
class BulkOperationStepperModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, declarations: [BulkOperationStepper, CustomStep], imports: [CoreModule,
DeviceSelectorModule,
CreateBulkOperationDetailsModule,
OperationSummaryModule], exports: [BulkOperationStepper, CustomStep] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, imports: [CoreModule,
DeviceSelectorModule,
CreateBulkOperationDetailsModule,
OperationSummaryModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, decorators: [{
type: NgModule,
args: [{
imports: [
CoreModule,
DeviceSelectorModule,
CreateBulkOperationDetailsModule,
OperationSummaryModule
],
declarations: [BulkOperationStepper, CustomStep],
exports: [BulkOperationStepper, CustomStep]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { BaseStepperComponent, BulkOperationStepper, BulkOperationStepperModule, CustomStep };
//# sourceMappingURL=c8y-ngx-components-operations-bulk-operation-stepper.mjs.map